--- a/src/protocols/sametime/meanwhile/cipher.c Wed Nov 02 03:31:38 2005 +0000 +++ b/src/protocols/sametime/meanwhile/cipher.c Wed Nov 02 03:39:03 2005 +0000 @@ -22,6 +22,9 @@ #include <string.h> #include <time.h> +#include <gmp.h> + + #include "mw_channel.h" #include "mw_cipher.h" #include "mw_debug.h" @@ -65,7 +68,82 @@ }; -void rand_key(char *key, gsize keylen) { +/** prime number used in DH exchange */ +static unsigned char dh_prime[] = { + 0xCF, 0x84, 0xAF, 0xCE, 0x86, 0xDD, 0xFA, 0x52, + 0x7F, 0x13, 0x6D, 0x10, 0x35, 0x75, 0x28, 0xEE, + 0xFB, 0xA0, 0xAF, 0xEF, 0x80, 0x8F, 0x29, 0x17, + 0x4E, 0x3B, 0x6A, 0x9E, 0x97, 0x00, 0x01, 0x71, + 0x7C, 0x8F, 0x10, 0x6C, 0x41, 0xC1, 0x61, 0xA6, + 0xCE, 0x91, 0x05, 0x7B, 0x34, 0xDA, 0x62, 0xCB, + 0xB8, 0x7B, 0xFD, 0xC1, 0xB3, 0x5C, 0x1B, 0x91, + 0x0F, 0xEA, 0x72, 0x24, 0x9D, 0x56, 0x6B, 0x9F +}; + + +/** base used in DH exchange */ +#define DH_BASE 3 + + +void mwInitDHPrime(mpz_t z) { + mpz_init(z); + mpz_import(z, 64, 1, 1, 0, 0, dh_prime); +} + + +void mwInitDHBase(mpz_t z) { + mpz_init_set_ui(z, DH_BASE); +} + + +void mwDHRandKeypair(mpz_t private, mpz_t public) { + gmp_randstate_t rstate; + mpz_t prime, base; + + mwInitDHPrime(prime); + mwInitDHBase(base); + + gmp_randinit_default(rstate); + mpz_urandomb(private, rstate, 512); + mpz_powm(public, base, private, prime); + + mpz_clear(prime); + mpz_clear(base); + gmp_randclear(rstate); +} + + +void mwDHCalculateShared(mpz_t shared, mpz_t remote, mpz_t private) { + mpz_t prime; + + mwInitDHPrime(prime); + mpz_powm(shared, remote, private, prime); + mpz_clear(prime); +} + + +void mwDHImportKey(mpz_t key, struct mwOpaque *o) { + g_return_if_fail(o != NULL); + mpz_import(key, o->len, 1, 1, 1, 0, o->data); +} + + +void mwDHExportKey(mpz_t key, struct mwOpaque *o) { + gsize needed; + + g_return_if_fail(o != NULL); + + needed = (mpz_sizeinbase(key,2) + 7) / 8; + o->len = 65; + o->data = g_malloc0(o->len); + + mpz_export(o->data+(o->len-needed), NULL, 1, 1, 1, 0, key); +} + + +void mwKeyRandom(char *key, gsize keylen) { + g_return_if_fail(key != NULL); + srand(clock()); while(keylen--) key[keylen] = rand() & 0xff; } @@ -76,13 +154,6 @@ 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }; memcpy(iv, normal_iv, 8); - - /* - *iv++ = 0x01; *iv++ = 0x23; - *iv++ = 0x45; *iv++ = 0x67; - *iv++ = 0x89; *iv++ = 0xab; - *iv++ = 0xcd; *iv = 0xef; - */ } @@ -93,14 +164,15 @@ char tmp[128]; int i, j; - /* - g_message("expanding key from:"); - pretty_print(key, keylen); - */ + g_return_if_fail(keylen > 0); + g_return_if_fail(key != NULL); if(keylen > 128) keylen = 128; + + /* fill the first chunk with what key bytes we have */ memcpy(tmp, key, keylen); + /* build the remaining key from the given data */ for(i = 0; keylen < 128; i++) { tmp[keylen] = PT[ (tmp[keylen - 1] + tmp[i]) & 0xff ]; keylen++; @@ -117,12 +189,14 @@ /* normal RC2 encryption given a full 128-byte (as 64 ints) key */ static void mwEncryptBlock(const int *ekey, char *out) { - int a = (out[7] << 8) | (out[6] & 0xff); - int b = (out[5] << 8) | (out[4] & 0xff); - int c = (out[3] << 8) | (out[2] & 0xff); - int d = (out[1] << 8) | (out[0] & 0xff); + + int a, b, c, d; + int i, j; - int i, j; + a = (out[7] << 8) | (out[6] & 0xff); + b = (out[5] << 8) | (out[4] & 0xff); + c = (out[3] << 8) | (out[2] & 0xff); + d = (out[1] << 8) | (out[0] & 0xff); for(i = 0; i < 16; i++) { j = i * 4; @@ -204,12 +278,14 @@ static void mwDecryptBlock(const int *ekey, char *out) { - int a = (out[7] << 8) | (out[6] & 0xff); - int b = (out[5] << 8) | (out[4] & 0xff); - int c = (out[3] << 8) | (out[2] & 0xff); - int d = (out[1] << 8) | (out[0] & 0xff); + + int a, b, c, d; + int i, j; - int i, j; + a = (out[7] << 8) | (out[6] & 0xff); + b = (out[5] << 8) | (out[4] & 0xff); + c = (out[3] << 8) | (out[2] & 0xff); + d = (out[1] << 8) | (out[0] & 0xff); for(i = 16; i--; ) { j = i * 4 + 3; @@ -293,6 +369,7 @@ } + struct mwCipher_RC2_40 { struct mwCipher cipher; int session_key[64]; @@ -358,20 +435,16 @@ } -static struct mwCipherInstance *new_instance_RC2_40(struct mwCipher *cipher, - struct mwChannel *chan) { +static struct mwCipherInstance * +new_instance_RC2_40(struct mwCipher *cipher, + struct mwChannel *chan) { + struct mwCipher_RC2_40 *cr; struct mwCipherInstance_RC2_40 *cir; struct mwCipherInstance *ci; cr = (struct mwCipher_RC2_40 *) cipher; - cir = g_new0(struct mwCipherInstance_RC2_40, 1); - ci = &cir->instance; - - ci->cipher = cipher; - ci->channel = chan; - /* a bit of lazy initialization here */ if(! cr->ready) { struct mwLoginInfo *info = mwSession_getLoginInfo(cipher->session); @@ -379,6 +452,12 @@ cr->ready = TRUE; } + cir = g_new0(struct mwCipherInstance_RC2_40, 1); + ci = &cir->instance; + + ci->cipher = cipher; + ci->channel = chan; + mwIV_init(cir->incoming_iv); mwIV_init(cir->outgoing_iv); @@ -387,24 +466,40 @@ static struct mwEncryptItem *new_item_RC2_40(struct mwCipherInstance *ci) { - struct mwEncryptItem *e = g_new0(struct mwEncryptItem, 1); + struct mwEncryptItem *e; + + e = g_new0(struct mwEncryptItem, 1); e->id = mwCipher_RC2_40; return e; } -static void accept_RC2_40(struct mwCipherInstance *ci) { - struct mwCipherInstance_RC2_40 *cir; - struct mwLoginInfo *info = mwChannel_getUser(ci->channel); - - cir = (struct mwCipherInstance_RC2_40 *) ci; - mwKeyExpand(cir->incoming_key, info->login_id, 5); +static struct mwEncryptItem * +offer_RC2_40(struct mwCipherInstance *ci) { + return new_item_RC2_40(ci); } static void accepted_RC2_40(struct mwCipherInstance *ci, struct mwEncryptItem *item) { - accept_RC2_40(ci); + + struct mwCipherInstance_RC2_40 *cir; + struct mwLoginInfo *info; + + cir = (struct mwCipherInstance_RC2_40 *) ci; + info = mwChannel_getUser(ci->channel); + + if(info->login_id) { + mwKeyExpand(cir->incoming_key, info->login_id, 5); + } +} + + +static struct mwEncryptItem * +accept_RC2_40(struct mwCipherInstance *ci) { + + accepted_RC2_40(ci, NULL); + return new_item_RC2_40(ci); } @@ -417,7 +512,8 @@ c->get_name = get_name_RC2_40; c->get_desc = get_desc_RC2_40; c->new_instance = new_instance_RC2_40; - c->new_item = new_item_RC2_40; + + c->offer = offer_RC2_40; c->accepted = accepted_RC2_40; c->accept = accept_RC2_40; @@ -429,6 +525,202 @@ } +struct mwCipher_RC2_128 { + struct mwCipher cipher; + mpz_t private_key; + struct mwOpaque public_key; +}; + + +struct mwCipherInstance_RC2_128 { + struct mwCipherInstance instance; + int shared[64]; /* shared secret determined via DH exchange */ + char outgoing_iv[8]; + char incoming_iv[8]; +}; + + +static const char *get_name_RC2_128() { + return "RC2/128 Cipher"; +} + + +static const char *get_desc_RC2_128() { + return "RC2, DH shared secret key"; +} + + +static struct mwCipherInstance * +new_instance_RC2_128(struct mwCipher *cipher, + struct mwChannel *chan) { + + struct mwCipher_RC2_128 *cr; + struct mwCipherInstance_RC2_128 *cir; + struct mwCipherInstance *ci; + + cr = (struct mwCipher_RC2_128 *) cipher; + + cir = g_new0(struct mwCipherInstance_RC2_128, 1); + ci = &cir->instance; + + ci->cipher = cipher; + ci->channel = chan; + + mwIV_init(cir->incoming_iv); + mwIV_init(cir->outgoing_iv); + + return ci; +} + + +static void offered_RC2_128(struct mwCipherInstance *ci, + struct mwEncryptItem *item) { + + mpz_t remote_key; + mpz_t shared; + struct mwOpaque sho = { 0, 0 }; + + struct mwCipher *c; + struct mwCipher_RC2_128 *cr; + struct mwCipherInstance_RC2_128 *cir; + + c = ci->cipher; + cr = (struct mwCipher_RC2_128 *) c; + cir = (struct mwCipherInstance_RC2_128 *) ci; + + mpz_init(remote_key); + mpz_init(shared); + + mwDHImportKey(remote_key, &item->info); + mwDHCalculateShared(shared, remote_key, cr->private_key); + mwDHExportKey(shared, &sho); + + /* key expanded from the last 16 bytes of the DH shared secret. This + took me forever to figure out. 16 bytes is 128 bit. */ + /* the sh_len-16 is important, because the key len could + hypothetically start with 8bits or more unset, meaning the + exported key might be less than 64 bytes in length */ + mwKeyExpand(cir->shared, sho.data+(sho.len-16), 16); + + mpz_clear(remote_key); + mpz_clear(shared); + mwOpaque_clear(&sho); +} + + +static struct mwEncryptItem * +offer_RC2_128(struct mwCipherInstance *ci) { + + struct mwCipher *c; + struct mwCipher_RC2_128 *cr; + struct mwEncryptItem *ei; + + c = ci->cipher; + cr = (struct mwCipher_RC2_128 *) c; + + ei = g_new0(struct mwEncryptItem, 1); + ei->id = mwCipher_RC2_128; + mwOpaque_clone(&ei->info, &cr->public_key); + + return ei; +} + + +static void accepted_RC2_128(struct mwCipherInstance *ci, + struct mwEncryptItem *item) { + + return offered_RC2_128(ci, item); +} + + +static struct mwEncryptItem * +accept_RC2_128(struct mwCipherInstance *ci) { + + return offer_RC2_128(ci); +} + + +static int encrypt_RC2_128(struct mwCipherInstance *ci, + struct mwOpaque *data) { + + struct mwCipherInstance_RC2_128 *cir; + struct mwOpaque o = { 0, 0 }; + + cir = (struct mwCipherInstance_RC2_128 *) ci; + + mwEncryptExpanded(cir->shared, cir->outgoing_iv, data, &o); + + mwOpaque_clear(data); + data->data = o.data; + data->len = o.len; + + return 0; +} + + +static int decrypt_RC2_128(struct mwCipherInstance *ci, + struct mwOpaque *data) { + + struct mwCipherInstance_RC2_128 *cir; + struct mwOpaque o = { 0, 0 }; + + cir = (struct mwCipherInstance_RC2_128 *) ci; + + mwDecryptExpanded(cir->shared, cir->incoming_iv, data, &o); + + mwOpaque_clear(data); + data->data = o.data; + data->len = o.len; + + return 0; +} + + +static void clear_RC2_128(struct mwCipher *c) { + struct mwCipher_RC2_128 *cr; + cr = (struct mwCipher_RC2_128 *) c; + + mpz_clear(cr->private_key); + mwOpaque_clear(&cr->public_key); +} + + +struct mwCipher *mwCipher_new_RC2_128(struct mwSession *s) { + struct mwCipher_RC2_128 *cr; + struct mwCipher *c; + + mpz_t pubkey; + + cr = g_new0(struct mwCipher_RC2_128, 1); + c = &cr->cipher; + + c->session = s; + c->type = mwCipher_RC2_128; + c->get_name = get_name_RC2_128; + c->get_desc = get_desc_RC2_128; + c->new_instance = new_instance_RC2_128; + + c->offered = offered_RC2_128; + c->offer = offer_RC2_128; + + c->accepted = accepted_RC2_128; + c->accept = accept_RC2_128; + + c->encrypt = encrypt_RC2_128; + c->decrypt = decrypt_RC2_128; + + c->clear = clear_RC2_128; + + mpz_init(cr->private_key); + mpz_init(pubkey); + mwDHRandKeypair(cr->private_key, pubkey); + mwDHExportKey(pubkey, &cr->public_key); + mpz_clear(pubkey); + + return c; +} + + struct mwSession *mwCipher_getSession(struct mwCipher *cipher) { g_return_val_if_fail(cipher != NULL, NULL); return cipher->session; @@ -437,8 +729,8 @@ guint16 mwCipher_getType(struct mwCipher *cipher) { /* oh man, this is a bad failover... who the hell decided to make - zero a real cipher id?? */ - g_return_val_if_fail(cipher != NULL, 0x00); + zero a real cipher id? */ + g_return_val_if_fail(cipher != NULL, 0xffff); return cipher->type; } @@ -514,15 +806,16 @@ } -void mwCipherInstance_offer(struct mwCipherInstance *ci) { +struct mwEncryptItem * +mwCipherInstance_offer(struct mwCipherInstance *ci) { struct mwCipher *cipher; - g_return_if_fail(ci != NULL); + g_return_val_if_fail(ci != NULL, NULL); cipher = ci->cipher; - g_return_if_fail(cipher != NULL); + g_return_val_if_fail(cipher != NULL, NULL); - if(cipher->offer) cipher->offer(ci); + return cipher->offer(ci); } @@ -539,15 +832,16 @@ } -void mwCipherInstance_accept(struct mwCipherInstance *ci) { +struct mwEncryptItem * +mwCipherInstance_accept(struct mwCipherInstance *ci) { struct mwCipher *cipher; - g_return_if_fail(ci != NULL); + g_return_val_if_fail(ci != NULL, NULL); cipher = ci->cipher; - g_return_if_fail(cipher != NULL); + g_return_val_if_fail(cipher != NULL, NULL); - if(cipher->accept) cipher->accept(ci); + return cipher->accept(ci); }