Fixed counter mode encryption/decryption.
authorPekka Riikonen <priikone@silcnet.org>
Sun, 18 Feb 2007 19:56:07 +0000 (19:56 +0000)
committerPekka Riikonen <priikone@silcnet.org>
Sun, 18 Feb 2007 19:56:07 +0000 (19:56 +0000)
The silc_cipher_set_iv in CTR mode now resets for a new block.

16 files changed:
lib/silccore/silcpacket.c
lib/silccrypt/aes.c
lib/silccrypt/aes.h
lib/silccrypt/blowfish.c
lib/silccrypt/blowfish.h
lib/silccrypt/cast.c
lib/silccrypt/cast.h
lib/silccrypt/none.c
lib/silccrypt/none.h
lib/silccrypt/rc5.c
lib/silccrypt/rc5.h
lib/silccrypt/silccipher.c
lib/silccrypt/silccipher.h
lib/silccrypt/twofish.c
lib/silccrypt/twofish.h
lib/silcske/silcske.c

index 661fbbe47e53eff3bee4c8c0c19035ae1ef43ea2..93ed46d56ac6698c73d8fa18ed1c8644d3717f78 100644 (file)
@@ -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) {
index bb78fd166bf88675fe9e366902c2a58c679686fd..88877978407582fd38ea1357c69ec10ad1025391 100644 (file)
@@ -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);
index d5bf528f28c9780706c3187a4ccaf0e54b59caca..9711c3fa07a6d81437e182fddbeb510b48f2df64 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  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
  */
 
 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);
index 860787a330c54574044fb97be8b3e8a464f95091..c1b11b29fe268371f1e2df7d26e0dd9580adc22a 100644 (file)
@@ -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)
index 2a76db06a561803b742fbb8ccf5a599c7cd0ec0f..996f7fe97f10e96506e9548e23aae9add826bbae 100644 (file)
@@ -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);
index e1e1a816ad47fc06f060f79116c0c1a9d71b21ff..65b9f1d29ce5caa9ce9c259d4db71c9a8944427a 100644 (file)
@@ -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)
index 092a1cf05718f27507b54be8a234a790e6af15ef..383b9fdde207472484f1f93a158cdd824e638d65 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  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);
index d8b790121c5af70cb382c64e9527edbb586f8a85..d35a85e2273578903f9d5fcd92be49590cec0149 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  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;
 }
index b0f3a38ba602be8bf3767981c921438a0aec8fdb..555ffa293ddd99b70b68177124d2d212a1430ae0 100644 (file)
@@ -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);
index ea377c5814e10ce2a507f85ec33943d7f3326714..290d311089e27306fdc4a0b4c2c2cfc76dd9b2ac 100644 (file)
@@ -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)
index d269c66118d0e0f4bc294ed12b4f6c39bfb2fe97..3adbee4cf75e9d871a05b7c865f07bb161b1ce25 100644 (file)
@@ -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);
index c5b0c4ae67abc5c889bde0ad1b9f5266aa6f5a5d..ee722690356263061f8b04078ad169468296f2e4 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  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. */
index 25083699b37060e634a2f89331e8589e9c5b1378..3afede61ea8c486e5a4175c601005046d3149d87 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  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);
index ced96d3df4f76b239551b26f33a1815beb17d17f..e8f3bd44d88dc0fc961dea93b21b029b3ebed6f2 100644 (file)
@@ -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)
index ba845960c0d6c4a8208659fe59f5c2b435aed306..afdcecd9af008679cdae6ab2c21826e1a69e0754 100644 (file)
@@ -4,7 +4,7 @@
 
   Author: Pekka Riikonen <priikone@silcnet.org>
 
-  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);
index 33ec0cdf5822ec5ba4fb7cd6cfc80a0a11c26bee..a726174339bde711d2108432905668a7fbc5fb37 100644 (file)
@@ -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);