libpurple/ciphers/descipher.c

Sat, 11 Jul 2015 14:45:46 -0400

author
James Geboski <jgeboski@gmail.com>
date
Sat, 11 Jul 2015 14:45:46 -0400
branch
facebook
changeset 37293
dc35ba3e7fac
parent 35094
47964e26263e
permissions
-rw-r--r--

facebook: fixed all errors being marked as fatal

/*
 * Original des taken from gpg
 *
 * des.c - DES encryption/decryption Algorithm
 *  Copyright (C) 1998 Free Software Foundation, Inc.
 *
 *  Please see below for more legal information!
 *
 *   According to the definition of DES in FIPS PUB 46-2 from December 1993.
 *   For a description of triple encryption, see:
 *     Bruce Schneier: Applied Cryptography. Second Edition.
 *     John Wiley & Sons, 1996. ISBN 0-471-12845-7. Pages 358 ff.
 *
 * Purple is the legal property of its developers, whose names are too numerous
 * to list here.  Please refer to the COPYRIGHT file distributed with this
 * source distribution.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
 */
#include "internal.h"
#include "glibcompat.h"

#include "descipher.h"
#include "enums.h"

#include <string.h>

/******************************************************************************
 * Structs
 *****************************************************************************/
#define PURPLE_DES_CIPHER_GET_PRIVATE(obj) \
	(G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_DES_CIPHER, PurpleDESCipherPrivate))

typedef struct {
	guint32 encrypt_subkeys[32];
	guint32 decrypt_subkeys[32];
} PurpleDESCipherPrivate;

/******************************************************************************
 * Enums
 *****************************************************************************/
enum {
	PROP_NONE,
	PROP_KEY,
	PROP_LAST,
};

/******************************************************************************
 * Globals
 *****************************************************************************/
static GObjectClass *parent_class = NULL;
static GParamSpec *properties[PROP_LAST];

/*
 *  The s-box values are permuted according to the 'primitive function P'
 */
static guint32 sbox1[64] = {
	0x00808200, 0x00000000, 0x00008000, 0x00808202, 0x00808002, 0x00008202,
	0x00000002, 0x00008000, 0x00000200, 0x00808200, 0x00808202, 0x00000200,
	0x00800202, 0x00808002, 0x00800000, 0x00000002, 0x00000202, 0x00800200,
	0x00800200, 0x00008200, 0x00008200, 0x00808000, 0x00808000, 0x00800202,
	0x00008002, 0x00800002, 0x00800002, 0x00008002, 0x00000000, 0x00000202,
	0x00008202, 0x00800000, 0x00008000, 0x00808202, 0x00000002, 0x00808000,
	0x00808200, 0x00800000, 0x00800000, 0x00000200, 0x00808002, 0x00008000,
	0x00008200, 0x00800002, 0x00000200, 0x00000002, 0x00800202, 0x00008202,
	0x00808202, 0x00008002, 0x00808000, 0x00800202, 0x00800002, 0x00000202,
	0x00008202, 0x00808200, 0x00000202, 0x00800200, 0x00800200, 0x00000000,
	0x00008002, 0x00008200, 0x00000000, 0x00808002
};

static guint32 sbox2[64] = {
	0x40084010, 0x40004000, 0x00004000, 0x00084010, 0x00080000, 0x00000010,
	0x40080010, 0x40004010, 0x40000010, 0x40084010, 0x40084000, 0x40000000,
	0x40004000, 0x00080000, 0x00000010, 0x40080010, 0x00084000, 0x00080010,
	0x40004010, 0x00000000, 0x40000000, 0x00004000, 0x00084010, 0x40080000,
	0x00080010, 0x40000010, 0x00000000, 0x00084000, 0x00004010, 0x40084000,
	0x40080000, 0x00004010, 0x00000000, 0x00084010, 0x40080010, 0x00080000,
	0x40004010, 0x40080000, 0x40084000, 0x00004000, 0x40080000, 0x40004000,
	0x00000010, 0x40084010, 0x00084010, 0x00000010, 0x00004000, 0x40000000,
	0x00004010, 0x40084000, 0x00080000, 0x40000010, 0x00080010, 0x40004010,
	0x40000010, 0x00080010, 0x00084000, 0x00000000, 0x40004000, 0x00004010,
	0x40000000, 0x40080010, 0x40084010, 0x00084000
};

static guint32 sbox3[64] = {
	0x00000104, 0x04010100, 0x00000000, 0x04010004, 0x04000100, 0x00000000,
	0x00010104, 0x04000100, 0x00010004, 0x04000004, 0x04000004, 0x00010000,
	0x04010104, 0x00010004, 0x04010000, 0x00000104, 0x04000000, 0x00000004,
	0x04010100, 0x00000100, 0x00010100, 0x04010000, 0x04010004, 0x00010104,
	0x04000104, 0x00010100, 0x00010000, 0x04000104, 0x00000004, 0x04010104,
	0x00000100, 0x04000000, 0x04010100, 0x04000000, 0x00010004, 0x00000104,
	0x00010000, 0x04010100, 0x04000100, 0x00000000, 0x00000100, 0x00010004,
	0x04010104, 0x04000100, 0x04000004, 0x00000100, 0x00000000, 0x04010004,
	0x04000104, 0x00010000, 0x04000000, 0x04010104, 0x00000004, 0x00010104,
	0x00010100, 0x04000004, 0x04010000, 0x04000104, 0x00000104, 0x04010000,
	0x00010104, 0x00000004, 0x04010004, 0x00010100
};

static guint32 sbox4[64] = {
	0x80401000, 0x80001040, 0x80001040, 0x00000040, 0x00401040, 0x80400040,
	0x80400000, 0x80001000, 0x00000000, 0x00401000, 0x00401000, 0x80401040,
	0x80000040, 0x00000000, 0x00400040, 0x80400000, 0x80000000, 0x00001000,
	0x00400000, 0x80401000, 0x00000040, 0x00400000, 0x80001000, 0x00001040,
	0x80400040, 0x80000000, 0x00001040, 0x00400040, 0x00001000, 0x00401040,
	0x80401040, 0x80000040, 0x00400040, 0x80400000, 0x00401000, 0x80401040,
	0x80000040, 0x00000000, 0x00000000, 0x00401000, 0x00001040, 0x00400040,
	0x80400040, 0x80000000, 0x80401000, 0x80001040, 0x80001040, 0x00000040,
	0x80401040, 0x80000040, 0x80000000, 0x00001000, 0x80400000, 0x80001000,
	0x00401040, 0x80400040, 0x80001000, 0x00001040, 0x00400000, 0x80401000,
	0x00000040, 0x00400000, 0x00001000, 0x00401040
};

static guint32 sbox5[64] = {
	0x00000080, 0x01040080, 0x01040000, 0x21000080, 0x00040000, 0x00000080,
	0x20000000, 0x01040000, 0x20040080, 0x00040000, 0x01000080, 0x20040080,
	0x21000080, 0x21040000, 0x00040080, 0x20000000, 0x01000000, 0x20040000,
	0x20040000, 0x00000000, 0x20000080, 0x21040080, 0x21040080, 0x01000080,
	0x21040000, 0x20000080, 0x00000000, 0x21000000, 0x01040080, 0x01000000,
	0x21000000, 0x00040080, 0x00040000, 0x21000080, 0x00000080, 0x01000000,
	0x20000000, 0x01040000, 0x21000080, 0x20040080, 0x01000080, 0x20000000,
	0x21040000, 0x01040080, 0x20040080, 0x00000080, 0x01000000, 0x21040000,
	0x21040080, 0x00040080, 0x21000000, 0x21040080, 0x01040000, 0x00000000,
	0x20040000, 0x21000000, 0x00040080, 0x01000080, 0x20000080, 0x00040000,
	0x00000000, 0x20040000, 0x01040080, 0x20000080
};

static guint32 sbox6[64] = {
	0x10000008, 0x10200000, 0x00002000, 0x10202008, 0x10200000, 0x00000008,
	0x10202008, 0x00200000, 0x10002000, 0x00202008, 0x00200000, 0x10000008,
	0x00200008, 0x10002000, 0x10000000, 0x00002008, 0x00000000, 0x00200008,
	0x10002008, 0x00002000, 0x00202000, 0x10002008, 0x00000008, 0x10200008,
	0x10200008, 0x00000000, 0x00202008, 0x10202000, 0x00002008, 0x00202000,
	0x10202000, 0x10000000, 0x10002000, 0x00000008, 0x10200008, 0x00202000,
	0x10202008, 0x00200000, 0x00002008, 0x10000008, 0x00200000, 0x10002000,
	0x10000000, 0x00002008, 0x10000008, 0x10202008, 0x00202000, 0x10200000,
	0x00202008, 0x10202000, 0x00000000, 0x10200008, 0x00000008, 0x00002000,
	0x10200000, 0x00202008, 0x00002000, 0x00200008, 0x10002008, 0x00000000,
	0x10202000, 0x10000000, 0x00200008, 0x10002008
};

static guint32 sbox7[64] = {
	0x00100000, 0x02100001, 0x02000401, 0x00000000, 0x00000400, 0x02000401,
	0x00100401, 0x02100400, 0x02100401, 0x00100000, 0x00000000, 0x02000001,
	0x00000001, 0x02000000, 0x02100001, 0x00000401, 0x02000400, 0x00100401,
	0x00100001, 0x02000400, 0x02000001, 0x02100000, 0x02100400, 0x00100001,
	0x02100000, 0x00000400, 0x00000401, 0x02100401, 0x00100400, 0x00000001,
	0x02000000, 0x00100400, 0x02000000, 0x00100400, 0x00100000, 0x02000401,
	0x02000401, 0x02100001, 0x02100001, 0x00000001, 0x00100001, 0x02000000,
	0x02000400, 0x00100000, 0x02100400, 0x00000401, 0x00100401, 0x02100400,
	0x00000401, 0x02000001, 0x02100401, 0x02100000, 0x00100400, 0x00000000,
	0x00000001, 0x02100401, 0x00000000, 0x00100401, 0x02100000, 0x00000400,
	0x02000001, 0x02000400, 0x00000400, 0x00100001
};

static guint32 sbox8[64] = {
	0x08000820, 0x00000800, 0x00020000, 0x08020820, 0x08000000, 0x08000820,
	0x00000020, 0x08000000, 0x00020020, 0x08020000, 0x08020820, 0x00020800,
	0x08020800, 0x00020820, 0x00000800, 0x00000020, 0x08020000, 0x08000020,
	0x08000800, 0x00000820, 0x00020800, 0x00020020, 0x08020020, 0x08020800,
	0x00000820, 0x00000000, 0x00000000, 0x08020020, 0x08000020, 0x08000800,
	0x00020820, 0x00020000, 0x00020820, 0x00020000, 0x08020800, 0x00000800,
	0x00000020, 0x08020020, 0x00000800, 0x00020820, 0x08000800, 0x00000020,
	0x08000020, 0x08020000, 0x08020020, 0x08000000, 0x00020000, 0x08000820,
	0x00000000, 0x08020820, 0x00020020, 0x08000020, 0x08020000, 0x08000800,
	0x08000820, 0x00000000, 0x08020820, 0x00020800, 0x00020800, 0x00000820,
	0x00000820, 0x00020020, 0x08000000, 0x08020800
};

/*
 * These two tables are part of the 'permuted choice 1' function.
 * In this implementation several speed improvements are done.
 */
static guint32 leftkey_swap[16] = {
	0x00000000, 0x00000001, 0x00000100, 0x00000101, 0x00010000, 0x00010001,
	0x00010100, 0x00010101, 0x01000000, 0x01000001, 0x01000100, 0x01000101,
	0x01010000, 0x01010001, 0x01010100, 0x01010101
};

static guint32 rightkey_swap[16] = {
	0x00000000, 0x01000000, 0x00010000, 0x01010000, 0x00000100, 0x01000100,
	0x00010100, 0x01010100, 0x00000001, 0x01000001, 0x00010001, 0x01010001,
	0x00000101, 0x01000101, 0x00010101, 0x01010101,
};

/*
 *  Numbers of left shifts per round for encryption subkey schedule
 *  To calculate the decryption key scheduling we just reverse the
 *  ordering of the subkeys so we can omit the table for decryption
 *  subkey schedule.
 */
static guint8 encrypt_rotate_tab[16] = {
	1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
};


/******************************************************************************
 * Helpers
 *****************************************************************************/
/*
 * Macro to swap bits across two words
 */
#define DO_PERMUTATION(a, temp, b, offset, mask)	\
	temp = ((a>>offset) ^ b) & mask;				\
	b ^= temp;										\
	a ^= temp<<offset;

/*
 * This performs the 'initial permutation' for the data to be encrypted or
 * decrypted
 */
#define INITIAL_PERMUTATION(left, temp, right)			\
	DO_PERMUTATION(left, temp, right, 4, 0x0f0f0f0f)	\
	DO_PERMUTATION(left, temp, right, 16, 0x0000ffff)	\
	DO_PERMUTATION(right, temp, left, 2, 0x33333333)	\
	DO_PERMUTATION(right, temp, left, 8, 0x00ff00ff)	\
	DO_PERMUTATION(left, temp, right, 1, 0x55555555)

/*
 * The 'inverse initial permutation'
 */
#define FINAL_PERMUTATION(left, temp, right)			\
    DO_PERMUTATION(left, temp, right, 1, 0x55555555)	\
	DO_PERMUTATION(right, temp, left, 8, 0x00ff00ff)	\
	DO_PERMUTATION(right, temp, left, 2, 0x33333333)	\
	DO_PERMUTATION(left, temp, right, 16, 0x0000ffff)	\
	DO_PERMUTATION(left, temp, right, 4, 0x0f0f0f0f)

/*
 * A full DES round including 'expansion function', 'sbox substitution'
 * and 'primitive function P' but without swapping the left and right word.
 */
#define DES_ROUND(from, to, work, subkey)			\
	work = ((from<<1) | (from>>31)) ^ *subkey++;	\
	to ^= sbox8[  work      & 0x3f ];				\
	to ^= sbox6[ (work>>8)  & 0x3f ];				\
	to ^= sbox4[ (work>>16) & 0x3f ];				\
	to ^= sbox2[ (work>>24) & 0x3f ];				\
	work = ((from>>3) | (from<<29)) ^ *subkey++;	\
	to ^= sbox7[  work      & 0x3f ];				\
	to ^= sbox5[ (work>>8)  & 0x3f ];				\
	to ^= sbox3[ (work>>16) & 0x3f ];				\
	to ^= sbox1[ (work>>24) & 0x3f ];


/*
 * Macros to convert 8 bytes from/to 32bit words
 */
#define READ_64BIT_DATA(data, left, right)									\
	left  = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];	\
	right = (data[4] << 24) | (data[5] << 16) | (data[6] << 8) | data[7];

#define WRITE_64BIT_DATA(data, left, right)							\
	data[0] = (left >> 24) &0xff; data[1] = (left >> 16) &0xff;		\
	data[2] = (left >> 8) &0xff; data[3] = left &0xff;				\
	data[4] = (right >> 24) &0xff; data[5] = (right >> 16) &0xff;	\
	data[6] = (right >> 8) &0xff; data[7] = right &0xff;

/******************************************************************************
 * Cipher Stuff
 *****************************************************************************/
/*
 * des_key_schedule():    Calculate 16 subkeys pairs (even/odd) for
 *            16 encryption rounds.
 *            To calculate subkeys for decryption the caller
 *                have to reorder the generated subkeys.
 *
 *        rawkey:       8 Bytes of key data
 *        subkey:       Array of at least 32 guint32s. Will be filled
 *              with calculated subkeys.
 *
 */
static void
purple_des_cipher_key_schedule(const guint8 * rawkey, guint32 * subkey) {
	guint32 left, right, work;
	int round;

	READ_64BIT_DATA (rawkey, left, right)

	DO_PERMUTATION (right, work, left, 4, 0x0f0f0f0f)
	DO_PERMUTATION (right, work, left, 0, 0x10101010)

	left = (leftkey_swap[(left >>  0) & 0xf] << 3)
		 | (leftkey_swap[(left >>  8) & 0xf] << 2)
		 | (leftkey_swap[(left >> 16) & 0xf] << 1)
		 | (leftkey_swap[(left >> 24) & 0xf]     )
		 | (leftkey_swap[(left >>  5) & 0xf] << 7)
		 | (leftkey_swap[(left >> 13) & 0xf] << 6)
		 | (leftkey_swap[(left >> 21) & 0xf] << 5)
		 | (leftkey_swap[(left >> 29) & 0xf] << 4);

	left &= 0x0fffffff;

	right = (rightkey_swap[(right >>  1) & 0xf] << 3)
		  | (rightkey_swap[(right >>  9) & 0xf] << 2)
		  | (rightkey_swap[(right >> 17) & 0xf] << 1)
		  | (rightkey_swap[(right >> 25) & 0xf]     )
		  | (rightkey_swap[(right >>  4) & 0xf] << 7)
		  | (rightkey_swap[(right >> 12) & 0xf] << 6)
		  | (rightkey_swap[(right >> 20) & 0xf] << 5)
		  | (rightkey_swap[(right >> 28) & 0xf] << 4);

	right &= 0x0fffffff;

	for (round = 0; round < 16; ++round) {
		left = ((left << encrypt_rotate_tab[round]) |
			    (left >> (28 - encrypt_rotate_tab[round]))) & 0x0fffffff;
		right = ((right << encrypt_rotate_tab[round]) |
				 (right >> (28 - encrypt_rotate_tab[round]))) & 0x0fffffff;

		*subkey++ = ((left  <<  4) & 0x24000000)
				  | ((left  << 28) & 0x10000000)
				  | ((left  << 14) & 0x08000000)
				  | ((left  << 18) & 0x02080000)
				  | ((left  <<  6) & 0x01000000)
				  | ((left  <<  9) & 0x00200000)
				  | ((left  >>  1) & 0x00100000)
				  | ((left  << 10) & 0x00040000)
				  | ((left  <<  2) & 0x00020000)
				  | ((left  >> 10) & 0x00010000)
				  | ((right >> 13) & 0x00002000)
				  | ((right >>  4) & 0x00001000)
				  | ((right <<  6) & 0x00000800)
				  | ((right >>  1) & 0x00000400)
				  | ((right >> 14) & 0x00000200)
				  | (right         & 0x00000100)
				  | ((right >>  5) & 0x00000020)
				  | ((right >> 10) & 0x00000010)
				  | ((right >>  3) & 0x00000008)
				  | ((right >> 18) & 0x00000004)
				  | ((right >> 26) & 0x00000002)
				  | ((right >> 24) & 0x00000001);

		*subkey++ = ((left  << 15) & 0x20000000)
				  | ((left  << 17) & 0x10000000)
				  | ((left  << 10) & 0x08000000)
				  | ((left  << 22) & 0x04000000)
				  | ((left  >>  2) & 0x02000000)
				  | ((left  <<  1) & 0x01000000)
				  | ((left  << 16) & 0x00200000)
				  | ((left  << 11) & 0x00100000)
				  | ((left  <<  3) & 0x00080000)
				  | ((left  >>  6) & 0x00040000)
				  | ((left  << 15) & 0x00020000)
				  | ((left  >>  4) & 0x00010000)
				  | ((right >>  2) & 0x00002000)
				  | ((right <<  8) & 0x00001000)
				  | ((right >> 14) & 0x00000808)
				  | ((right >>  9) & 0x00000400)
				  | ((right)       & 0x00000200)
				  | ((right <<  7) & 0x00000100)
				  | ((right >>  7) & 0x00000020)
				  | ((right >>  3) & 0x00000011)
				  | ((right <<  2) & 0x00000004)
				  | ((right >> 21) & 0x00000002);
	}
}

/*
 * Fill a DES context with subkeys calculated from a 64bit key.
 * Does not check parity bits, but simply ignore them.
 * Does not check for weak keys.
 */
static void
purple_des_cipher_set_key(PurpleCipher *cipher, const guchar *key, size_t len) {
	PurpleDESCipher *des_cipher = PURPLE_DES_CIPHER(cipher);
	PurpleDESCipherPrivate *priv = PURPLE_DES_CIPHER_GET_PRIVATE(des_cipher);
	int i;

	g_return_if_fail(len == 8);

	purple_des_cipher_key_schedule(key, priv->encrypt_subkeys);

	for(i = 0; i < 32; i += 2) {
		priv->decrypt_subkeys[i] = priv->encrypt_subkeys[30 - i];
		priv->decrypt_subkeys[i + 1] = priv->encrypt_subkeys[31 - i];
	}

	g_object_notify_by_pspec(G_OBJECT(cipher), properties[PROP_KEY]);
}

static size_t
purple_des_cipher_get_key_size(PurpleCipher *cipher)
{
	return 8;
}

/*
 * Electronic Codebook Mode DES encryption/decryption of data according to
 * 'mode'.
 */
int
purple_des_cipher_ecb_crypt(PurpleDESCipher *des_cipher, const guint8 * from, guint8 * to,
			  int mode)
{
	guint32 left, right, work;
	guint32 *keys;
	PurpleDESCipherPrivate *priv = PURPLE_DES_CIPHER_GET_PRIVATE(des_cipher);

	keys = mode ? priv->decrypt_subkeys :
				  priv->encrypt_subkeys;

	READ_64BIT_DATA (from, left, right)
	INITIAL_PERMUTATION (left, work, right)

	DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
	DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
	DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
	DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
	DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
	DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
	DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)
	DES_ROUND (right, left, work, keys) DES_ROUND (left, right, work, keys)

	FINAL_PERMUTATION (right, work, left)
	WRITE_64BIT_DATA (to, right, left)

	return 0;
}

static ssize_t
purple_des_cipher_encrypt(PurpleCipher *cipher, const guchar input[],
							size_t in_len, guchar output[], size_t out_size)
{
	PurpleDESCipher *des_cipher = PURPLE_DES_CIPHER(cipher);

	gsize offset = 0;
	int i = 0;
	gsize tmp;
	guint8 buf[8] = {0,0,0,0,0,0,0,0};
	gsize out_len;

	g_return_val_if_fail(out_size >= in_len, -1);

	while(offset + 8 <= in_len) {
		purple_des_cipher_ecb_crypt(des_cipher, input + offset, output + offset, 0);
		offset += 8;
	}

	out_len = in_len;

	if(offset<in_len) {
		g_return_val_if_fail(in_len >= offset, -1);
		out_len += in_len - offset;
		g_return_val_if_fail(out_size >= out_len, -1);
		tmp = offset;
		while(tmp<in_len) {
			buf[i++] = input[tmp];
			tmp++;
		}

		purple_des_cipher_ecb_crypt(des_cipher, buf, output + offset, 0);
	}

	return out_len;
}

static ssize_t
purple_des_cipher_decrypt(PurpleCipher *cipher, const guchar input[],
							size_t in_len, guchar output[], size_t out_size)
{
	PurpleDESCipher *des_cipher = PURPLE_DES_CIPHER(cipher);

	gsize offset = 0;
	int i = 0;
	gsize tmp;
	guint8 buf[8] = {0,0,0,0,0,0,0,0};
	gsize out_len;

	g_return_val_if_fail(out_size >= in_len, -1);

	while(offset + 8 <= in_len) {
		purple_des_cipher_ecb_crypt(des_cipher, input + offset, output + offset, 1);
		offset += 8;
	}

	out_len = in_len;
	if(offset<in_len) {
		g_return_val_if_fail(in_len >= offset, -1);
		out_len += in_len - offset;
		g_return_val_if_fail(out_size >= out_len, -1);
		tmp = offset;
		while(tmp<in_len) {
			buf[i++] = input[tmp];
			tmp++;
		}

		purple_des_cipher_ecb_crypt(des_cipher, buf, output + offset, 1);
	}

	return out_len;
}

/******************************************************************************
 * Object Stuff
 *****************************************************************************/
static void
purple_des_cipher_set_property(GObject *obj, guint param_id,
							   const GValue *value, GParamSpec *pspec)
{
	PurpleCipher *cipher = PURPLE_CIPHER(obj);

	switch(param_id) {
		case PROP_KEY:
			purple_cipher_set_key(cipher, (guchar *)g_value_get_string(value),
										purple_des_cipher_get_key_size(cipher));
			break;
		default:
			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
			break;
	}
}

static void
purple_des_cipher_class_init(PurpleDESCipherClass *klass)
{
	GObjectClass *obj_class = G_OBJECT_CLASS(klass);
	PurpleCipherClass *cipher_class = PURPLE_CIPHER_CLASS(klass);

	parent_class = g_type_class_peek_parent(klass);

	obj_class->set_property = purple_des_cipher_set_property;

	cipher_class->encrypt = purple_des_cipher_encrypt;
	cipher_class->decrypt = purple_des_cipher_decrypt;
	cipher_class->set_key = purple_des_cipher_set_key;
	cipher_class->get_key_size = purple_des_cipher_get_key_size;

	g_type_class_add_private(klass, sizeof(PurpleDESCipherPrivate));

	properties[PROP_KEY] = g_param_spec_string("key", "key", "key", NULL,
								G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS);

	g_object_class_install_properties(obj_class, PROP_LAST, properties);
}

/******************************************************************************
 * API
 *****************************************************************************/
GType
purple_des_cipher_get_type(void) {
	static GType type = 0;

	if(type == 0) {
		static const GTypeInfo info = {
			.class_size = sizeof(PurpleDESCipherClass),
			.class_init = (GClassInitFunc)purple_des_cipher_class_init,
			.instance_size = sizeof(PurpleDESCipher),
			.instance_init = (GInstanceInitFunc)purple_cipher_reset,
		};

		type = g_type_register_static(PURPLE_TYPE_CIPHER,
									  "PurpleDESCipher",
									  &info, 0);
	}

	return type;
}

/**
 * purple_des_cipher_new:
 *
 * Creates a new #PurpleCipher instance which implements the DES block cipher.
 *
 * Return Value: The new DES implementation of #PurpleCipher.
 */
PurpleCipher *
purple_des_cipher_new(void) {
	return g_object_new(PURPLE_TYPE_DES_CIPHER, NULL);
}

mercurial