Merge branch 'topic/mm-fixes' of git://208.110.73.182/silc into silc.1.1.branch
[silc.git] / lib / silccrypt / aes.c
index d05bb7684a0bfb717d88ff1c7f0452c19e856256..f41a61d66766ae4cfb547721a75acea0d82ad5dc 100644 (file)
  * SILC Crypto API for AES
  */
 
+/* CBC mode */
+
 /* Sets the key for the cipher. */
 
-SILC_CIPHER_API_SET_KEY(aes)
+SILC_CIPHER_API_SET_KEY(aes_cbc)
 {
   if (encryption)
     aes_encrypt_key(key, keylen, &((AesContext *)context)->u.enc);
@@ -52,9 +54,16 @@ SILC_CIPHER_API_SET_KEY(aes)
   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)
+SILC_CIPHER_API_CONTEXT_LEN(aes_cbc)
 {
   return sizeof(AesContext);
 }
@@ -62,16 +71,38 @@ SILC_CIPHER_API_CONTEXT_LEN(aes)
 /* Encrypts with the cipher in CBC mode. Source and destination buffers
    maybe one and same. */
 
-SILC_CIPHER_API_ENCRYPT_CBC(aes)
+SILC_CIPHER_API_ENCRYPT(aes_cbc)
 {
   int nb = len >> 4;
+  SilcUInt32 tmp[4], tmp2[4];
+
+  SILC_ASSERT((len & (16 - 1)) == 0);
+  if (len & (16 - 1))
+    return FALSE;
 
   while(nb--) {
-    lp32(iv)[0] ^= lp32(src)[0];
-    lp32(iv)[1] ^= lp32(src)[1];
-    lp32(iv)[2] ^= lp32(src)[2];
-    lp32(iv)[3] ^= lp32(src)[3];
+    SILC_GET32_MSB(tmp[0], &iv[0]);
+    SILC_GET32_MSB(tmp[1], &iv[4]);
+    SILC_GET32_MSB(tmp[2], &iv[8]);
+    SILC_GET32_MSB(tmp[3], &iv[12]);
+
+    SILC_GET32_MSB(tmp2[0], &src[0]);
+    SILC_GET32_MSB(tmp2[1], &src[4]);
+    SILC_GET32_MSB(tmp2[2], &src[8]);
+    SILC_GET32_MSB(tmp2[3], &src[12]);
+
+    tmp[0] = tmp[0] ^ tmp2[0];
+    tmp[1] = tmp[1] ^ tmp2[1];
+    tmp[2] = tmp[2] ^ tmp2[2];
+    tmp[3] = tmp[3] ^ tmp2[3];
+
+    SILC_PUT32_MSB(tmp[0], &iv[0]);
+    SILC_PUT32_MSB(tmp[1], &iv[4]);
+    SILC_PUT32_MSB(tmp[2], &iv[8]);
+    SILC_PUT32_MSB(tmp[3], &iv[12]);
+
     aes_encrypt(iv, iv, &((AesContext *)context)->u.enc);
+
     memcpy(dst, iv, 16);
     src += 16;
     dst += 16;
@@ -83,18 +114,39 @@ SILC_CIPHER_API_ENCRYPT_CBC(aes)
 /* Decrypts with the cipher in CBC mode. Source and destination buffers
    maybe one and same. */
 
-SILC_CIPHER_API_DECRYPT_CBC(aes)
+SILC_CIPHER_API_DECRYPT(aes_cbc)
 {
   unsigned char tmp[16];
   int nb = len >> 4;
+  SilcUInt32 tmp2[4], tmp3[4];
+
+  if (len & (16 - 1))
+    return FALSE;
 
   while(nb--) {
     memcpy(tmp, src, 16);
     aes_decrypt(src, dst, &((AesContext *)context)->u.dec);
-    lp32(dst)[0] ^= lp32(iv)[0];
-    lp32(dst)[1] ^= lp32(iv)[1];
-    lp32(dst)[2] ^= lp32(iv)[2];
-    lp32(dst)[3] ^= lp32(iv)[3];
+
+    SILC_GET32_MSB(tmp2[0], &iv[0]);
+    SILC_GET32_MSB(tmp2[1], &iv[4]);
+    SILC_GET32_MSB(tmp2[2], &iv[8]);
+    SILC_GET32_MSB(tmp2[3], &iv[12]);
+
+    SILC_GET32_MSB(tmp3[0], &dst[0]);
+    SILC_GET32_MSB(tmp3[1], &dst[4]);
+    SILC_GET32_MSB(tmp3[2], &dst[8]);
+    SILC_GET32_MSB(tmp3[3], &dst[12]);
+
+    tmp2[0] = tmp3[0] ^ tmp2[0];
+    tmp2[1] = tmp3[1] ^ tmp2[1];
+    tmp2[2] = tmp3[2] ^ tmp2[2];
+    tmp2[3] = tmp3[3] ^ tmp2[3];
+
+    SILC_PUT32_MSB(tmp2[0], &dst[0]);
+    SILC_PUT32_MSB(tmp2[1], &dst[4]);
+    SILC_PUT32_MSB(tmp2[2], &dst[8]);
+    SILC_PUT32_MSB(tmp2[3], &dst[12]);
+
     memcpy(iv, tmp, 16);
     src += 16;
     dst += 16;
@@ -103,6 +155,71 @@ SILC_CIPHER_API_DECRYPT_CBC(aes)
   return TRUE;
 }
 
+/* CTR mode */
+
+/* Sets the key for the cipher. */
+
+SILC_CIPHER_API_SET_KEY(aes_ctr)
+{
+  AesContext *aes = context;
+  memset(&aes->u.enc, 0, sizeof(aes->u.enc));
+  aes_encrypt_key(key, keylen, &aes->u.enc);
+  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)
+{
+  return sizeof(AesContext);
+}
+
+/* Encrypts with the cipher in CTR mode. Source and destination buffers
+   may be one and same.  Assumes MSB first ordered counter. */
+
+SILC_CIPHER_API_ENCRYPT(aes_ctr)
+{
+  AesContext *aes = context;
+  int i, k;
+
+  i = aes->u.enc.inf.b[2];
+  if (!i)
+    i = 16;
+
+  while (len-- > 0) {
+    if (i == 16) {
+      for (k = 15; k >= 0; k--)
+       if (++iv[k])
+         break;
+
+      aes_encrypt(iv, aes->u.enc.pad, &aes->u.enc);
+      i = 0;
+    }
+    *dst++ = *src++ ^ aes->u.enc.pad[i++];
+  }
+  aes->u.enc.inf.b[2] = i;
+
+  return TRUE;
+}
+
+/* Decrypts with the cipher in CTR mode. Source and destination buffers
+   maybe one and same. */
+
+SILC_CIPHER_API_DECRYPT(aes_ctr)
+{
+  return silc_aes_ctr_encrypt(context, src, dst, len, iv);
+}
+
 /****************************************************************************/
 
 #if defined(__cplusplus)
@@ -120,9 +237,9 @@ extern "C"
 #define d_4(t,n,b,e,f,g,h) ALIGN const XP_DIR t n[4][256] = { b(e), b(f), b(g), b(h) }
 ALIGN const uint_32t t_dec(r,c)[RC_LENGTH] = rc_data(w0);
 
-#ifdef SILC_ASM_AES
+#ifdef SILC_AES_ASM
 d_1(uint_8t, t_dec(i,box), isb_data, h0);
-#endif /* SILC_ASM_AES */
+#endif /* SILC_AES_ASM */
 d_4(uint_32t, t_dec(f,n), sb_data, u0, u1, u2, u3);
 d_4(uint_32t, t_dec(f,l), sb_data, w0, w1, w2, w3);
 d_4(uint_32t, t_dec(i,n), isb_data, v0, v1, v2, v3);
@@ -424,7 +541,7 @@ AES_RETURN aes_decrypt_key(const unsigned char *key, int key_len, aes_decrypt_ct
     }
 }
 
-#ifndef SILC_ASM_AES
+#ifndef SILC_AES_ASM
 /* C version of AES */
 
 #define si(y,x,k,c) (s(y,c) = word_in(x, c) ^ (k)[c])
@@ -533,4 +650,4 @@ AES_RETURN aes_decrypt(const unsigned char *in, unsigned char *out, const aes_de
 }
 #endif
 
-#endif /* SILC_ASM_AES */
+#endif /* SILC_AES_ASM */