Mercurial > pidgin > pidgin
view libpurple/ciphers/des3cipher.c @ 38351:d18a2256f3c5
Merged in CMaiku/pidgin (pull request #202)
gnomekeyring: Quiet Gnome Keyring function deprecations
Approved-by: Eion Robb <eionrobb@gmail.com>
Approved-by: Gary Kramlich <grim@reaperworld.com>
Approved-by: dx <dx@dxzone.com.ar>
author | Gary Kramlich <grim@reaperworld.com> |
---|---|
date | Thu, 15 Jun 2017 03:29:49 +0000 |
parents | 07cd7f1767c7 |
children |
line wrap: on
line source
/* * Original des taken from gpg * * des.c - Triple-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 "des3cipher.h" #include "descipher.h" #include "enums.h" #include <string.h> /****************************************************************************** * Structs *****************************************************************************/ #define PURPLE_DES3_CIPHER_GET_PRIVATE(obj) \ (G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_DES3_CIPHER, PurpleDES3CipherPrivate)) typedef struct _PurpleDES3CipherPrivate PurpleDES3CipherPrivate; struct _PurpleDES3CipherPrivate { PurpleCipherBatchMode mode; guchar iv[8]; /* First key for encryption */ PurpleCipher *key1; /* Second key for decryption */ PurpleCipher *key2; /* Third key for encryption */ PurpleCipher *key3; }; /****************************************************************************** * Enums *****************************************************************************/ enum { PROP_NONE, PROP_BATCH_MODE, PROP_IV, PROP_KEY, PROP_LAST, }; /****************************************************************************** * Globals *****************************************************************************/ static GObjectClass *parent_class = NULL; static GParamSpec *properties[PROP_LAST]; /****************************************************************************** * Cipher Stuff *****************************************************************************/ static size_t purple_des3_cipher_get_key_size(PurpleCipher *cipher) { return 24; } /* * Fill a DES3 context with subkeys calculated from 3 64bit key. * Does not check parity bits, but simply ignore them. * Does not check for weak keys. **/ static void purple_des3_cipher_set_key(PurpleCipher *cipher, const guchar *key, size_t len) { PurpleDES3Cipher *des3_cipher = PURPLE_DES3_CIPHER(cipher); PurpleDES3CipherPrivate *priv = PURPLE_DES3_CIPHER_GET_PRIVATE(des3_cipher); g_return_if_fail(len == 24); purple_cipher_set_key(PURPLE_CIPHER(priv->key1), key + 0, purple_cipher_get_key_size(PURPLE_CIPHER(priv->key1))); purple_cipher_set_key(PURPLE_CIPHER(priv->key2), key + 8, purple_cipher_get_key_size(PURPLE_CIPHER(priv->key2))); purple_cipher_set_key(PURPLE_CIPHER(priv->key3), key + 16, purple_cipher_get_key_size(PURPLE_CIPHER(priv->key3))); g_object_notify_by_pspec(G_OBJECT(cipher), properties[PROP_KEY]); } static ssize_t purple_des3_cipher_ecb_encrypt(PurpleDES3Cipher *des3_cipher, const guchar input[], size_t in_len, guchar output[], size_t out_size) { gsize offset = 0; int i = 0; gsize tmp; guint8 buf[8] = {0,0,0,0,0,0,0,0}; gsize out_len; PurpleDES3CipherPrivate *priv = PURPLE_DES3_CIPHER_GET_PRIVATE(des3_cipher); g_return_val_if_fail(out_size >= in_len, -1); while (offset + 8 <= in_len) { purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key1), input + offset, output + offset, 0); purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key2), output + offset, buf, 1); purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key3), buf, 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; memset(buf, 0, 8); while (tmp < in_len) { buf[i++] = input[tmp]; tmp++; } purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key1), buf, output + offset, 0); purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key2), output + offset, buf, 1); purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key3), buf, output + offset, 0); } return out_len; } static ssize_t purple_des3_cipher_cbc_encrypt(PurpleDES3Cipher *des3_cipher, const guchar input[], size_t in_len, guchar output[], size_t out_size) { gsize offset = 0; int i = 0; gsize tmp; guint8 buf[8]; gsize out_len; PurpleDES3CipherPrivate *priv = PURPLE_DES3_CIPHER_GET_PRIVATE(des3_cipher); memcpy(buf, priv->iv, 8); g_return_val_if_fail(out_size >= in_len, -1); while (offset + 8 <= in_len) { for (i = 0; i < 8; i++) buf[i] ^= input[offset + i]; purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key1), buf, output + offset, 0); purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key2), output + offset, buf, 1); purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key3), buf, output + offset, 0); memcpy(buf, output+offset, 8); 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; i = 0; while (tmp < in_len) { buf[i++] ^= input[tmp]; tmp++; } purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key1), buf, output + offset, 0); purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key2), output + offset, buf, 1); purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key3), buf, output + offset, 0); } return out_len; } static ssize_t purple_des3_cipher_encrypt(PurpleCipher *cipher, const guchar input[], size_t in_len, guchar output[], size_t out_size) { PurpleDES3Cipher *des3_cipher = PURPLE_DES3_CIPHER(cipher); PurpleDES3CipherPrivate *priv = PURPLE_DES3_CIPHER_GET_PRIVATE(des3_cipher); if (priv->mode == PURPLE_CIPHER_BATCH_MODE_ECB) { return purple_des3_cipher_ecb_encrypt(des3_cipher, input, in_len, output, out_size); } else if (priv->mode == PURPLE_CIPHER_BATCH_MODE_CBC) { return purple_des3_cipher_cbc_encrypt(des3_cipher, input, in_len, output, out_size); } else { g_return_val_if_reached(0); } return 0; } static ssize_t purple_des3_cipher_ecb_decrypt(PurpleDES3Cipher *des3_cipher, const guchar input[], size_t in_len, guchar output[], size_t out_size) { gsize offset = 0; int i = 0; gsize tmp; guint8 buf[8] = {0,0,0,0,0,0,0,0}; gsize out_len; PurpleDES3CipherPrivate *priv = PURPLE_DES3_CIPHER_GET_PRIVATE(des3_cipher); g_return_val_if_fail(out_size >= in_len, -1); while (offset + 8 <= in_len) { /* NOTE: Apply key in reverse */ purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key3), input + offset, output + offset, 1); purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key2), output + offset, buf, 0); purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key1), buf, 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; memset(buf, 0, 8); while (tmp < in_len) { buf[i++] = input[tmp]; tmp++; } purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key3), buf, output + offset, 1); purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key2), output + offset, buf, 0); purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key1), buf, output + offset, 1); } return out_len; } static ssize_t purple_des3_cipher_cbc_decrypt(PurpleDES3Cipher *des3_cipher, const guchar input[], size_t in_len, guchar output[], size_t out_size) { gsize offset = 0; int i = 0; gsize tmp; guint8 buf[8] = {0,0,0,0,0,0,0,0}; guint8 link[8]; gsize out_len; PurpleDES3CipherPrivate *priv = PURPLE_DES3_CIPHER_GET_PRIVATE(des3_cipher); g_return_val_if_fail(out_size >= in_len, -1); memcpy(link, priv->iv, 8); while (offset + 8 <= in_len) { purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key3), input + offset, output + offset, 1); purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key2), output + offset, buf, 0); purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key1), buf, output + offset, 1); for (i = 0; i < 8; i++) output[offset + i] ^= link[i]; memcpy(link, input + offset, 8); 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; memset(buf, 0, 8); i = 0; while(tmp<in_len) { buf[i++] = input[tmp]; tmp++; } purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key3), buf, output + offset, 1); purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key2), output + offset, buf, 0); purple_des_cipher_ecb_crypt(PURPLE_DES_CIPHER(priv->key1), buf, output + offset, 1); for (i = 0; i < 8; i++) output[offset + i] ^= link[i]; } return out_len; } static ssize_t purple_des3_cipher_decrypt(PurpleCipher *cipher, const guchar input[], size_t in_len, guchar output[], size_t out_size) { PurpleDES3Cipher *des3_cipher = PURPLE_DES3_CIPHER(cipher); PurpleDES3CipherPrivate *priv = PURPLE_DES3_CIPHER_GET_PRIVATE(cipher); if (priv->mode == PURPLE_CIPHER_BATCH_MODE_ECB) { return purple_des3_cipher_ecb_decrypt(des3_cipher, input, in_len, output, out_size); } else if (priv->mode == PURPLE_CIPHER_BATCH_MODE_CBC) { return purple_des3_cipher_cbc_decrypt(des3_cipher, input, in_len, output, out_size); } else { g_return_val_if_reached(0); } return 0; } static void purple_des3_cipher_set_batch_mode(PurpleCipher *cipher, PurpleCipherBatchMode mode) { PurpleDES3Cipher *des3_cipher = PURPLE_DES3_CIPHER(cipher); PurpleDES3CipherPrivate *priv = PURPLE_DES3_CIPHER_GET_PRIVATE(des3_cipher); priv->mode = mode; g_object_notify_by_pspec(G_OBJECT(cipher), properties[PROP_BATCH_MODE]); } static PurpleCipherBatchMode purple_des3_cipher_get_batch_mode(PurpleCipher *cipher) { PurpleDES3Cipher *des3_cipher = PURPLE_DES3_CIPHER(cipher); PurpleDES3CipherPrivate *priv = PURPLE_DES3_CIPHER_GET_PRIVATE(des3_cipher); return priv->mode; } static void purple_des3_cipher_set_iv(PurpleCipher *cipher, guchar *iv, size_t len) { PurpleDES3Cipher *des3_cipher = PURPLE_DES3_CIPHER(cipher); PurpleDES3CipherPrivate *priv = PURPLE_DES3_CIPHER_GET_PRIVATE(des3_cipher); g_return_if_fail(len == 8); memcpy(priv->iv, iv, len); g_object_notify_by_pspec(G_OBJECT(cipher), properties[PROP_IV]); } /****************************************************************************** * Object Stuff *****************************************************************************/ static void purple_des3_cipher_get_property(GObject *obj, guint param_id, GValue *value, GParamSpec *pspec) { PurpleCipher *cipher = PURPLE_CIPHER(obj); switch(param_id) { case PROP_BATCH_MODE: g_value_set_enum(value, purple_cipher_get_batch_mode(cipher)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); break; } } static void purple_des3_cipher_set_property(GObject *obj, guint param_id, const GValue *value, GParamSpec *pspec) { PurpleCipher *cipher = PURPLE_CIPHER(obj); switch(param_id) { case PROP_BATCH_MODE: purple_cipher_set_batch_mode(cipher, g_value_get_enum(value)); break; case PROP_IV: { guchar *iv = (guchar *)g_value_get_string(value); purple_cipher_set_iv(cipher, iv, strlen((gchar*)iv)); } break; case PROP_KEY: purple_cipher_set_key(cipher, (guchar *)g_value_get_string(value), purple_des3_cipher_get_key_size(cipher)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec); break; } } static void purple_des3_cipher_finalize(GObject *obj) { PurpleDES3Cipher *des3_cipher = PURPLE_DES3_CIPHER(obj); PurpleDES3CipherPrivate *priv = PURPLE_DES3_CIPHER_GET_PRIVATE(des3_cipher); g_object_unref(G_OBJECT(priv->key1)); g_object_unref(G_OBJECT(priv->key2)); g_object_unref(G_OBJECT(priv->key3)); memset(priv->iv, 0, sizeof(priv->iv)); parent_class->finalize(obj); } static void purple_des3_cipher_class_init(PurpleDES3CipherClass *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->finalize = purple_des3_cipher_finalize; obj_class->get_property = purple_des3_cipher_get_property; obj_class->set_property = purple_des3_cipher_set_property; cipher_class->set_iv = purple_des3_cipher_set_iv; cipher_class->encrypt = purple_des3_cipher_encrypt; cipher_class->decrypt = purple_des3_cipher_decrypt; cipher_class->set_key = purple_des3_cipher_set_key; cipher_class->set_batch_mode = purple_des3_cipher_set_batch_mode; cipher_class->get_batch_mode = purple_des3_cipher_get_batch_mode; cipher_class->get_key_size = purple_des3_cipher_get_key_size; g_type_class_add_private(klass, sizeof(PurpleDES3CipherPrivate)); 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_IV] = g_param_spec_string("iv", "iv", "iv", NULL, G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS); 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); } static void purple_des3_cipher_init(PurpleCipher *cipher) { PurpleDES3Cipher *des3_cipher = PURPLE_DES3_CIPHER(cipher); PurpleDES3CipherPrivate *priv = PURPLE_DES3_CIPHER_GET_PRIVATE(des3_cipher); priv->key1 = purple_des_cipher_new(); priv->key2 = purple_des_cipher_new(); priv->key3 = purple_des_cipher_new(); } /****************************************************************************** * API *****************************************************************************/ GType purple_des3_cipher_get_type(void) { static GType type = 0; if(type == 0) { static const GTypeInfo info = { sizeof(PurpleDES3CipherClass), NULL, NULL, (GClassInitFunc)purple_des3_cipher_class_init, NULL, NULL, sizeof(PurpleDES3Cipher), 0, (GInstanceInitFunc)purple_des3_cipher_init, NULL }; type = g_type_register_static(PURPLE_TYPE_CIPHER, "PurpleDES3Cipher", &info, 0); } return type; } PurpleCipher * purple_des3_cipher_new(void) { return g_object_new(PURPLE_TYPE_DES3_CIPHER, NULL); }