From fb1e58b1bc106212a845da866d0d4e9433c3ae22 Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Sun, 18 Feb 2007 19:56:07 +0000 Subject: [PATCH] Fixed counter mode encryption/decryption. The silc_cipher_set_iv in CTR mode now resets for a new block. --- lib/silccore/silcpacket.c | 34 ++++++++++++++++++++------------- lib/silccrypt/aes.c | 19 ++++++++++++++++++- lib/silccrypt/aes.h | 4 +++- lib/silccrypt/blowfish.c | 7 +++++++ lib/silccrypt/blowfish.h | 1 + lib/silccrypt/cast.c | 7 +++++++ lib/silccrypt/cast.h | 3 ++- lib/silccrypt/none.c | 11 ++++++++--- lib/silccrypt/none.h | 1 + lib/silccrypt/rc5.c | 7 +++++++ lib/silccrypt/rc5.h | 1 + lib/silccrypt/silccipher.c | 13 ++++++++----- lib/silccrypt/silccipher.h | 39 +++++++++++++++++++++++++++++++++++--- lib/silccrypt/twofish.c | 7 +++++++ lib/silccrypt/twofish.h | 3 ++- lib/silcske/silcske.c | 9 +++++---- 16 files changed, 134 insertions(+), 32 deletions(-) diff --git a/lib/silccore/silcpacket.c b/lib/silccore/silcpacket.c index 661fbbe4..93ed46d5 100644 --- a/lib/silccore/silcpacket.c +++ b/lib/silccore/silcpacket.c @@ -1373,12 +1373,15 @@ static inline void silc_packet_send_ctr_increment(SilcPacketStream stream, unsigned char *ret_iv) { unsigned char *iv = silc_cipher_get_iv(cipher); - SilcUInt32 pc; + SilcUInt32 pc1, pc2; - /* Increment packet counter */ - SILC_GET32_MSB(pc, iv + 8); - pc++; - SILC_PUT32_MSB(pc, iv + 8); + /* Increment 64-bit packet counter.*/ + SILC_GET32_MSB(pc1, iv + 4); + SILC_GET32_MSB(pc2, iv + 8); + if (++pc2 == 0) + ++pc1; + SILC_PUT32_MSB(pc1, iv + 4); + SILC_PUT32_MSB(pc2, iv + 8); /* Reset block counter */ memset(iv + 12, 0, 4); @@ -1390,7 +1393,7 @@ static inline void silc_packet_send_ctr_increment(SilcPacketStream stream, ret_iv[1] = ret_iv[0] + iv[4]; ret_iv[2] = ret_iv[0] ^ ret_iv[1]; ret_iv[3] = ret_iv[0] + ret_iv[2]; - SILC_PUT32_MSB(pc, ret_iv + 4); + SILC_PUT32_MSB(pc2, ret_iv + 4); SILC_LOG_HEXDUMP(("IV"), ret_iv, 8); /* Set new nonce to counter block */ @@ -1532,6 +1535,7 @@ static inline SilcBool silc_packet_send_raw(SilcPacketStream stream, /* Encrypt the packet */ if (silc_likely(cipher)) { SILC_LOG_DEBUG(("Encrypting packet")); + silc_cipher_set_iv(cipher, NULL); if (silc_unlikely(!silc_cipher_encrypt(cipher, packet.data + ivlen, packet.data + ivlen, enclen, NULL))) { @@ -1722,16 +1726,19 @@ static inline void silc_packet_receive_ctr_increment(SilcPacketStream stream, unsigned char *iv, unsigned char *packet_iv) { - SilcUInt32 pc; + SilcUInt32 pc1, pc2; /* If IV Included flag, set the IV from packet to block counter. */ if (stream->iv_included) { memcpy(iv + 4, packet_iv, 8); } else { - /* Increment packet counter */ - SILC_GET32_MSB(pc, iv + 8); - pc++; - SILC_PUT32_MSB(pc, iv + 8); + /* Increment 64-bit packet counter. */ + SILC_GET32_MSB(pc1, iv + 4); + SILC_GET32_MSB(pc2, iv + 8); + if (++pc2 == 0) + ++pc1; + SILC_PUT32_MSB(pc1, iv + 4); + SILC_PUT32_MSB(pc2, iv + 8); } /* Reset block counter */ @@ -2049,8 +2056,9 @@ static void silc_packet_read_process(SilcPacketStream stream) silc_packet_receive_ctr_increment(stream, iv, NULL); } - silc_cipher_decrypt(cipher, inbuf->data + ivlen, tmp, - block_len, iv); + if (silc_cipher_get_mode(cipher) == SILC_CIPHER_MODE_CTR) + silc_cipher_set_iv(cipher, NULL); + silc_cipher_decrypt(cipher, inbuf->data + ivlen, tmp, block_len, iv); header = tmp; if (stream->iv_included) { diff --git a/lib/silccrypt/aes.c b/lib/silccrypt/aes.c index bb78fd16..88877978 100644 --- a/lib/silccrypt/aes.c +++ b/lib/silccrypt/aes.c @@ -54,6 +54,13 @@ SILC_CIPHER_API_SET_KEY(aes_cbc) return TRUE; } +/* Sets IV for the cipher. */ + +SILC_CIPHER_API_SET_IV(aes_cbc) +{ + +} + /* Returns the size of the cipher context. */ SILC_CIPHER_API_CONTEXT_LEN(aes_cbc) @@ -124,6 +131,16 @@ SILC_CIPHER_API_SET_KEY(aes_ctr) return TRUE; } +/* Sets IV for the cipher. */ + +SILC_CIPHER_API_SET_IV(aes_ctr) +{ + AesContext *aes = context; + + /* Starts new block. */ + aes->u.enc.inf.b[2] = 0; +} + /* Returns the size of the cipher context. */ SILC_CIPHER_API_CONTEXT_LEN(aes_ctr) @@ -138,7 +155,7 @@ SILC_CIPHER_API_ENCRYPT(aes_ctr) { AesContext *aes = context; SilcUInt32 ctr[4]; - int i; + int i = 16; SILC_GET32_MSB(ctr[0], iv); SILC_GET32_MSB(ctr[1], iv + 4); diff --git a/lib/silccrypt/aes.h b/lib/silccrypt/aes.h index d5bf528f..9711c3fa 100644 --- a/lib/silccrypt/aes.h +++ b/lib/silccrypt/aes.h @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 1997 - 2006 Pekka Riikonen + Copyright (C) 1997 - 2007 Pekka Riikonen 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 @@ -25,10 +25,12 @@ */ SILC_CIPHER_API_SET_KEY(aes_cbc); +SILC_CIPHER_API_SET_IV(aes_cbc); SILC_CIPHER_API_ENCRYPT(aes_cbc); SILC_CIPHER_API_DECRYPT(aes_cbc); SILC_CIPHER_API_CONTEXT_LEN(aes_cbc); SILC_CIPHER_API_SET_KEY(aes_ctr); +SILC_CIPHER_API_SET_IV(aes_ctr); SILC_CIPHER_API_ENCRYPT(aes_ctr); SILC_CIPHER_API_DECRYPT(aes_ctr); SILC_CIPHER_API_CONTEXT_LEN(aes_ctr); diff --git a/lib/silccrypt/blowfish.c b/lib/silccrypt/blowfish.c index 860787a3..c1b11b29 100644 --- a/lib/silccrypt/blowfish.c +++ b/lib/silccrypt/blowfish.c @@ -49,6 +49,13 @@ SILC_CIPHER_API_SET_KEY(blowfish_cbc) return TRUE; } +/* Sets IV for the cipher. */ + +SILC_CIPHER_API_SET_IV(blowfish_cbc) +{ + +} + /* Returns the size of the cipher context. */ SILC_CIPHER_API_CONTEXT_LEN(blowfish_cbc) diff --git a/lib/silccrypt/blowfish.h b/lib/silccrypt/blowfish.h index 2a76db06..996f7fe9 100644 --- a/lib/silccrypt/blowfish.h +++ b/lib/silccrypt/blowfish.h @@ -25,6 +25,7 @@ */ SILC_CIPHER_API_SET_KEY(blowfish_cbc); +SILC_CIPHER_API_SET_IV(blowfish_cbc); SILC_CIPHER_API_CONTEXT_LEN(blowfish_cbc); SILC_CIPHER_API_ENCRYPT(blowfish_cbc); SILC_CIPHER_API_DECRYPT(blowfish_cbc); diff --git a/lib/silccrypt/cast.c b/lib/silccrypt/cast.c index e1e1a816..65b9f1d2 100644 --- a/lib/silccrypt/cast.c +++ b/lib/silccrypt/cast.c @@ -80,6 +80,13 @@ SILC_CIPHER_API_SET_KEY(cast_cbc) return TRUE; } +/* Sets IV for the cipher. */ + +SILC_CIPHER_API_SET_IV(cast_cbc) +{ + +} + /* Returns the size of the cipher context. */ SILC_CIPHER_API_CONTEXT_LEN(cast_cbc) diff --git a/lib/silccrypt/cast.h b/lib/silccrypt/cast.h index 092a1cf0..383b9fdd 100644 --- a/lib/silccrypt/cast.h +++ b/lib/silccrypt/cast.h @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 1999 - 2000, 2006 Pekka Riikonen + Copyright (C) 1999 - 2000, 2006, 2007 Pekka Riikonen 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 @@ -25,6 +25,7 @@ */ SILC_CIPHER_API_SET_KEY(cast_cbc); +SILC_CIPHER_API_SET_IV(cast_cbc); SILC_CIPHER_API_CONTEXT_LEN(cast_cbc); SILC_CIPHER_API_ENCRYPT(cast_cbc); SILC_CIPHER_API_DECRYPT(cast_cbc); diff --git a/lib/silccrypt/none.c b/lib/silccrypt/none.c index d8b79012..d35a85e2 100644 --- a/lib/silccrypt/none.c +++ b/lib/silccrypt/none.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 1997 - 2000 Pekka Riikonen + Copyright (C) 1997 - 2007 Pekka Riikonen 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 @@ -29,6 +29,11 @@ SILC_CIPHER_API_SET_KEY(none) return TRUE; } +SILC_CIPHER_API_SET_IV(none) +{ + +} + SILC_CIPHER_API_CONTEXT_LEN(none) { return 1; @@ -36,12 +41,12 @@ SILC_CIPHER_API_CONTEXT_LEN(none) SILC_CIPHER_API_ENCRYPT(none) { - memcpy(dst, src, len); + memmove(dst, src, len); return TRUE; } SILC_CIPHER_API_DECRYPT(none) { - memcpy(dst, src, len); + memmove(dst, src, len); return TRUE; } diff --git a/lib/silccrypt/none.h b/lib/silccrypt/none.h index b0f3a38b..555ffa29 100644 --- a/lib/silccrypt/none.h +++ b/lib/silccrypt/none.h @@ -25,6 +25,7 @@ */ SILC_CIPHER_API_SET_KEY(none); +SILC_CIPHER_API_SET_IV(none); SILC_CIPHER_API_CONTEXT_LEN(none); SILC_CIPHER_API_ENCRYPT(none); SILC_CIPHER_API_DECRYPT(none); diff --git a/lib/silccrypt/rc5.c b/lib/silccrypt/rc5.c index ea377c58..290d3110 100644 --- a/lib/silccrypt/rc5.c +++ b/lib/silccrypt/rc5.c @@ -58,6 +58,13 @@ SILC_CIPHER_API_SET_KEY(rc5_cbc) return TRUE; } +/* Sets IV for the cipher. */ + +SILC_CIPHER_API_SET_IV(rc5_cbc) +{ + +} + /* Returns the size of the cipher context. */ SILC_CIPHER_API_CONTEXT_LEN(rc5_cbc) diff --git a/lib/silccrypt/rc5.h b/lib/silccrypt/rc5.h index d269c661..3adbee4c 100644 --- a/lib/silccrypt/rc5.h +++ b/lib/silccrypt/rc5.h @@ -25,6 +25,7 @@ */ SILC_CIPHER_API_SET_KEY(rc5_cbc); +SILC_CIPHER_API_SET_IV(rc5_cbc); SILC_CIPHER_API_CONTEXT_LEN(rc5_cbc); SILC_CIPHER_API_ENCRYPT(rc5_cbc); SILC_CIPHER_API_DECRYPT(rc5_cbc); diff --git a/lib/silccrypt/silccipher.c b/lib/silccrypt/silccipher.c index c5b0c4ae..ee722690 100644 --- a/lib/silccrypt/silccipher.c +++ b/lib/silccrypt/silccipher.c @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 1997 - 2006 Pekka Riikonen + Copyright (C) 1997 - 2007 Pekka Riikonen 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 @@ -35,9 +35,9 @@ SilcDList silc_cipher_list = NULL; /* Macro to define cipher to cipher list */ #define SILC_CIPHER_API_DEF(name, cipher, keylen, blocklen, ivlen, mode) \ -{ name, silc_##cipher##_set_key, silc_##cipher##_encrypt, \ - silc_##cipher##_decrypt, silc_##cipher##_context_len, \ - keylen, blocklen, ivlen, mode } +{ name, silc_##cipher##_set_key, silc_##cipher##_set_iv, \ + silc_##cipher##_encrypt, silc_##cipher##_decrypt, \ + silc_##cipher##_context_len, keylen, blocklen, ivlen, mode } /* Static list of ciphers for silc_cipher_register_default(). */ const SilcCipherObject silc_default_ciphers[] = @@ -100,6 +100,7 @@ SilcBool silc_cipher_register(const SilcCipherObject *cipher) new->block_len = cipher->block_len; new->iv_len = cipher->iv_len; new->set_key = cipher->set_key; + new->set_iv = cipher->set_iv; new->encrypt = cipher->encrypt; new->decrypt = cipher->decrypt; new->context_len = cipher->context_len; @@ -331,7 +332,9 @@ SilcBool silc_cipher_set_key(SilcCipher cipher, const unsigned char *key, void silc_cipher_set_iv(SilcCipher cipher, const unsigned char *iv) { - memcpy(&cipher->iv, iv, cipher->cipher->iv_len); + if (iv) + memmove(&cipher->iv, iv, cipher->cipher->iv_len); + cipher->cipher->set_iv(cipher->context, iv); } /* Returns the IV (initial vector) of the cipher. */ diff --git a/lib/silccrypt/silccipher.h b/lib/silccrypt/silccipher.h index 25083699..3afede61 100644 --- a/lib/silccrypt/silccipher.h +++ b/lib/silccrypt/silccipher.h @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 1997 - 2006 Pekka Riikonen + Copyright (C) 1997 - 2007 Pekka Riikonen 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 @@ -50,6 +50,7 @@ typedef struct SilcCipherStruct *SilcCipher; typedef struct { char *name; SilcBool (*set_key)(void *, const unsigned char *, SilcUInt32, SilcBool); + void (*set_iv)(void *, const unsigned char *); SilcBool (*encrypt)(void *, const unsigned char *, unsigned char *, SilcUInt32, unsigned char *); SilcBool (*decrypt)(void *, const unsigned char *, unsigned char *, @@ -91,6 +92,9 @@ SilcBool silc_##cipher##_set_key(void *context, \ const unsigned char *key, \ SilcUInt32 keylen, \ SilcBool encryption) +#define SILC_CIPHER_API_SET_IV(cipher) \ +void silc_##cipher##_set_iv(void *context, \ + const unsigned char *iv) #define SILC_CIPHER_API_ENCRYPT(cipher) \ SilcBool silc_##cipher##_encrypt(void *context, \ const unsigned char *src, \ @@ -191,7 +195,7 @@ SilcBool silc_cipher_unregister_all(void); * SYNOPSIS * * SilcBool silc_cipher_alloc(const unsigned char *name, - * SilcCipher *new_cipher); + * SilcCipher *new_cipher); * * DESCRIPTION * @@ -200,6 +204,31 @@ SilcBool silc_cipher_unregister_all(void); * caller must set the key to the cipher after this function has returned * by calling the ciphers set_key function. * + * The following ciphers are supported: + * + * aes-256-ctr AES-256, Counter mode + * aes-192-ctr AES-192, Counter mode + * aes-128-ctr AES,128, Counter mode + * aes-256-cbc AES-256, Cipher block chaining mode + * aes-192-cbc AES-192, Cipher block chaining mode + * aes-128-cbc AES,128, Cipher block chaining mode + * twofish-256-cbc Twofish-256, Cipher block chaining mode + * twofish-192-cbc Twofish-192, Cipher block chaining mode + * twofish-128-cbc Twofish-128, Cipher block chaining mode + * + * Notes about modes: + * + * The CTR is normal counter mode. The CTR mode does not require the + * plaintext length to be multiple by the cipher block size. If the last + * plaintext block is shorter the remaining bits of the key stream are + * used next time silc_cipher_encrypt is called. If silc_cipher_set_iv + * is called it will reset the counter for a new block (discarding any + * remaining bits from previous key stream). + * + * The CBC is mode is a standard CBC mode. The plaintext length must be + * multiple by the cipher block size. If it isn't the plaintext must be + * padded. + * ***/ SilcBool silc_cipher_alloc(const unsigned char *name, SilcCipher *new_cipher); @@ -308,7 +337,11 @@ SilcBool silc_cipher_set_key(SilcCipher cipher, const unsigned char *key, * DESCRIPTION * * Sets the IV (initial vector) for the cipher. The `iv' must be - * the size of the block size of the cipher. + * the size of the block size of the cipher. If `iv' is NULL this + * does not do anything. + * + * If the encryption mode is CTR (Counter mode) this also resets the + * the counter for a new block. This is done also if `iv' is NULL. * ***/ void silc_cipher_set_iv(SilcCipher cipher, const unsigned char *iv); diff --git a/lib/silccrypt/twofish.c b/lib/silccrypt/twofish.c index ced96d3d..e8f3bd44 100644 --- a/lib/silccrypt/twofish.c +++ b/lib/silccrypt/twofish.c @@ -59,6 +59,13 @@ SILC_CIPHER_API_SET_KEY(twofish_cbc) return TRUE; } +/* Sets IV for the cipher. */ + +SILC_CIPHER_API_SET_IV(twofish_cbc) +{ + +} + /* Returns the size of the cipher context. */ SILC_CIPHER_API_CONTEXT_LEN(twofish_cbc) diff --git a/lib/silccrypt/twofish.h b/lib/silccrypt/twofish.h index ba845960..afdcecd9 100644 --- a/lib/silccrypt/twofish.h +++ b/lib/silccrypt/twofish.h @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 1997 - 2000 Pekka Riikonen + Copyright (C) 1997 - 2007 Pekka Riikonen 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 @@ -25,6 +25,7 @@ */ SILC_CIPHER_API_SET_KEY(twofish_cbc); +SILC_CIPHER_API_SET_IV(twofish_cbc); SILC_CIPHER_API_CONTEXT_LEN(twofish_cbc); SILC_CIPHER_API_ENCRYPT(twofish_cbc); SILC_CIPHER_API_DECRYPT(twofish_cbc); diff --git a/lib/silcske/silcske.c b/lib/silcske/silcske.c index 33ec0cdf..a7261743 100644 --- a/lib/silcske/silcske.c +++ b/lib/silcske/silcske.c @@ -3016,6 +3016,7 @@ SilcBool silc_ske_set_keys(SilcSKE ske, SilcHash *ret_hash) { unsigned char iv[32]; + SilcBool iv_included = (prop->flags & SILC_SKE_SP_FLAG_IV_INCLUDED); /* Allocate ciphers to be used in the communication */ if (ret_send_key) { @@ -3050,7 +3051,7 @@ SilcBool silc_ske_set_keys(SilcSKE ske, if (silc_cipher_get_mode(*ret_send_key) == SILC_CIPHER_MODE_CTR) { memcpy(iv, ske->hash, 4); - memcpy(iv + 4, keymat->receive_iv, 4); + memcpy(iv + 4, keymat->receive_iv, iv_included ? 4 : 8); silc_cipher_set_iv(*ret_send_key, iv); } else { silc_cipher_set_iv(*ret_send_key, keymat->receive_iv); @@ -3062,7 +3063,7 @@ SilcBool silc_ske_set_keys(SilcSKE ske, if (silc_cipher_get_mode(*ret_receive_key) == SILC_CIPHER_MODE_CTR) { memcpy(iv, ske->hash, 4); - memcpy(iv + 4, keymat->send_iv, 4); + memcpy(iv + 4, keymat->send_iv, iv_included ? 4 : 8); silc_cipher_set_iv(*ret_receive_key, iv); } else { silc_cipher_set_iv(*ret_receive_key, keymat->send_iv); @@ -3081,7 +3082,7 @@ SilcBool silc_ske_set_keys(SilcSKE ske, if (silc_cipher_get_mode(*ret_send_key) == SILC_CIPHER_MODE_CTR) { memcpy(iv, ske->hash, 4); - memcpy(iv + 4, keymat->send_iv, 4); + memcpy(iv + 4, keymat->send_iv, iv_included ? 4 : 8); silc_cipher_set_iv(*ret_send_key, iv); } else { silc_cipher_set_iv(*ret_send_key, keymat->send_iv); @@ -3093,7 +3094,7 @@ SilcBool silc_ske_set_keys(SilcSKE ske, if (silc_cipher_get_mode(*ret_receive_key) == SILC_CIPHER_MODE_CTR) { memcpy(iv, ske->hash, 4); - memcpy(iv + 4, keymat->receive_iv, 4); + memcpy(iv + 4, keymat->receive_iv, iv_included ? 4 : 8); silc_cipher_set_iv(*ret_receive_key, iv); } else { silc_cipher_set_iv(*ret_receive_key, keymat->receive_iv); -- 2.24.0