pidgin/pidgin

Adapt migration for files
xdg-dirs
2016-10-02, qarkai
d6ebc5c97d74
Adapt migration for files
/*
* 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);
}