--- a/libpurple/ciphers/aescipher.c Thu Apr 03 00:47:13 2014 +0200
+++ b/libpurple/ciphers/aescipher.c Thu Apr 03 03:52:31 2014 +0200
@@ -58,6 +58,7 @@
+ PurpleCipherBatchMode batch_mode; } PurpleAESCipherPrivate;
/******************************************************************************
@@ -82,7 +83,8 @@
typedef gboolean (*purple_aes_cipher_crypt_func)(
const guchar *input, guchar *output, size_t len,
- guchar iv[PURPLE_AES_BLOCK_SIZE], guchar key[32], guint key_size);
+ guchar iv[PURPLE_AES_BLOCK_SIZE], guchar key[32], guint key_size, + PurpleCipherBatchMode batch_mode); purple_aes_cipher_reset(PurpleCipher *cipher)
@@ -232,11 +234,32 @@
purple_aes_cipher_gnutls_encrypt(const guchar *input, guchar *output, size_t len,
- guchar iv[PURPLE_AES_BLOCK_SIZE], guchar key[32], guint key_size)
+ guchar iv[PURPLE_AES_BLOCK_SIZE], guchar key[32], guint key_size, + PurpleCipherBatchMode batch_mode) gnutls_cipher_hd_t handle;
+ /* We have to simulate ECB mode, which is not supported by GnuTLS. */ + if (batch_mode == PURPLE_CIPHER_BATCH_MODE_ECB) { + for (i = 0; i < len / PURPLE_AES_BLOCK_SIZE; i++) { + int offset = i * PURPLE_AES_BLOCK_SIZE; + guchar iv_local[PURPLE_AES_BLOCK_SIZE]; + memcpy(iv_local, iv, sizeof(iv_local)); + succ = purple_aes_cipher_gnutls_encrypt( + input + offset, output + offset, + iv_local, key, key_size, + PURPLE_CIPHER_BATCH_MODE_CBC); handle = purple_aes_cipher_gnutls_crypt_init(iv, key, key_size);
@@ -255,11 +278,32 @@
purple_aes_cipher_gnutls_decrypt(const guchar *input, guchar *output, size_t len,
- guchar iv[PURPLE_AES_BLOCK_SIZE], guchar key[32], guint key_size)
+ guchar iv[PURPLE_AES_BLOCK_SIZE], guchar key[32], guint key_size, + PurpleCipherBatchMode batch_mode) gnutls_cipher_hd_t handle;
+ /* We have to simulate ECB mode, which is not supported by GnuTLS. */ + if (batch_mode == PURPLE_CIPHER_BATCH_MODE_ECB) { + for (i = 0; i < len / PURPLE_AES_BLOCK_SIZE; i++) { + int offset = i * PURPLE_AES_BLOCK_SIZE; + guchar iv_local[PURPLE_AES_BLOCK_SIZE]; + memcpy(iv_local, iv, sizeof(iv_local)); + succ = purple_aes_cipher_gnutls_decrypt( + input + offset, output + offset, + iv_local, key, key_size, + PURPLE_CIPHER_BATCH_MODE_CBC); handle = purple_aes_cipher_gnutls_crypt_init(iv, key, key_size);
@@ -305,10 +349,9 @@
purple_aes_cipher_nss_crypt(const guchar *input, guchar *output, size_t len,
guchar iv[PURPLE_AES_BLOCK_SIZE], guchar key[32], guint key_size,
- CK_ATTRIBUTE_TYPE operation)
+ CK_ATTRIBUTE_TYPE operation, CK_MECHANISM_TYPE cipher_mech) PurpleAESCipherNSSContext context;
- CK_MECHANISM_TYPE cipher_mech = CKM_AES_CBC;
SECItem key_item, iv_item;
@@ -385,28 +428,41 @@
if (outlen != (int)len) {
purple_debug_error("cipher-aes",
- "resulting length doesn't match: %d (expected: %lu)\n",
+ "resulting length doesn't match: %d (expected: %" + G_GSIZE_FORMAT ")\n", outlen, len); +static CK_MECHANISM_TYPE +purple_aes_cipher_nss_batch_mode(PurpleCipherBatchMode batch_mode) + case PURPLE_CIPHER_BATCH_MODE_CBC: + case PURPLE_CIPHER_BATCH_MODE_ECB: purple_aes_cipher_nss_encrypt(const guchar *input, guchar *output, size_t len,
- guchar iv[PURPLE_AES_BLOCK_SIZE], guchar key[32], guint key_size)
+ guchar iv[PURPLE_AES_BLOCK_SIZE], guchar key[32], guint key_size, + PurpleCipherBatchMode batch_mode) return purple_aes_cipher_nss_crypt(input, output, len, iv, key, key_size,
+ CKA_ENCRYPT, purple_aes_cipher_nss_batch_mode(batch_mode)); purple_aes_cipher_nss_decrypt(const guchar *input, guchar *output, size_t len,
- guchar iv[PURPLE_AES_BLOCK_SIZE], guchar key[32], guint key_size)
+ guchar iv[PURPLE_AES_BLOCK_SIZE], guchar key[32], guint key_size, + PurpleCipherBatchMode batch_mode) return purple_aes_cipher_nss_crypt(input, output, len, iv, key, key_size,
+ CKA_DECRYPT, purple_aes_cipher_nss_batch_mode(batch_mode)); #endif /* PURPLE_AES_USE_NSS */
@@ -427,7 +483,8 @@
input_padded = purple_aes_cipher_pad_pkcs7(input, in_len, &out_len);
if (out_len > out_size) {
- purple_debug_error("cipher-aes", "Output buffer too small\n");
+ purple_debug_error("cipher-aes", + "Output buffer too small (%d > %d)", out_len, out_size); memset(input_padded, 0, out_len);
@@ -443,7 +500,7 @@
succ = encrypt_func(input_padded, output, out_len, priv->iv,
- priv->key, priv->key_size);
+ priv->key, priv->key_size, priv->batch_mode); memset(input_padded, 0, out_len);
@@ -488,7 +545,7 @@
succ = decrypt_func(input, output, in_len, priv->iv, priv->key,
+ priv->key_size, priv->batch_mode); memset(output, 0, in_len);
@@ -518,18 +575,24 @@
PurpleAESCipherPrivate *priv = PURPLE_AES_CIPHER_GET_PRIVATE(cipher);
- if (mode != PURPLE_CIPHER_BATCH_MODE_CBC) {
+ if (mode != PURPLE_CIPHER_BATCH_MODE_CBC && + mode != PURPLE_CIPHER_BATCH_MODE_ECB) purple_debug_error("cipher-aes", "unsupported batch mode\n");
+ priv->batch_mode = mode; g_object_notify_by_pspec(G_OBJECT(cipher), properties[PROP_BATCH_MODE]);
static PurpleCipherBatchMode
purple_aes_cipher_get_batch_mode(PurpleCipher *cipher)
- return PURPLE_CIPHER_BATCH_MODE_CBC;
+ PurpleAESCipherPrivate *priv = PURPLE_AES_CIPHER_GET_PRIVATE(cipher); + return priv->batch_mode; @@ -605,9 +668,10 @@
g_type_class_add_private(klass, sizeof(PurpleAESCipherPrivate));
- properties[PROP_BATCH_MODE] = g_param_spec_enum("batch-mode", "batch-mode",
- "batch-mode", PURPLE_TYPE_CIPHER_BATCH_MODE, 0,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ properties[PROP_BATCH_MODE] = g_param_spec_enum("batch-mode", + "batch-mode", "batch-mode", PURPLE_TYPE_CIPHER_BATCH_MODE, + PURPLE_CIPHER_BATCH_MODE_CBC, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS); properties[PROP_IV] = g_param_spec_string("iv", "iv", "iv", NULL,
G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS);