AES-CFB[18] 2x optimization. Well, I bet nobody cares about AES-CFB1
[openssl.git] / crypto / aes / aes_cfb.c
index 9b2917298a8f74cd950c69cd66442440d2ad40ca..49f0411010c371a0285ca22280a7f1ff1f609fb4 100644 (file)
  * [including the GNU Public Licence.]
  */
 
+#ifndef AES_DEBUG
+# ifndef NDEBUG
+#  define NDEBUG
+# endif
+#endif
 #include <assert.h>
+
 #include <openssl/aes.h>
 #include "aes_locl.h"
+#include "e_os.h"
 
 /* The input and output encrypted as though 128bit cfb mode is being
  * used.  The extra state information to record how much of the
@@ -137,7 +144,7 @@ void AES_cfb128_encrypt(const unsigned char *in, unsigned char *out,
        } else {
                while (l--) {
                        if (n == 0) {
-                               AES_decrypt(ivec, ivec, key);
+                               AES_encrypt(ivec, ivec, key);
                        }
                        c = *(in);
                        *(out++) = *(in++) ^ ivec[n];
@@ -149,3 +156,70 @@ void AES_cfb128_encrypt(const unsigned char *in, unsigned char *out,
        *num=n;
 }
 
+/* This expects a single block of size nbits for both in and out. Note that
+   it corrupts any extra bits in the last byte of out */
+void AES_cfbr_encrypt_block(const unsigned char *in,unsigned char *out,
+                           const int nbits,const AES_KEY *key,
+                           unsigned char *ivec,const int enc)
+    {
+    int n,rem,num;
+    unsigned char ovec[AES_BLOCK_SIZE*2];
+
+    if (nbits<=0 || nbits>128) return;
+
+       /* fill in the first half of the new IV with the current IV */
+       memcpy(ovec,ivec,AES_BLOCK_SIZE);
+       /* construct the new IV */
+       AES_encrypt(ivec,ivec,key);
+       num = (nbits+7)/8;
+       if (enc)        /* encrypt the input */
+           for(n=0 ; n < num ; ++n)
+               out[n] = (ovec[AES_BLOCK_SIZE+n] = in[n] ^ ivec[n]);
+       else            /* decrypt the input */
+           for(n=0 ; n < num ; ++n)
+               out[n] = (ovec[AES_BLOCK_SIZE+n] = in[n]) ^ ivec[n];
+       /* shift ovec left... */
+       rem = nbits%8;
+       num = nbits/8;
+       if(rem==0)
+           memcpy(ivec,ovec+num,AES_BLOCK_SIZE);
+       else
+           for(n=0 ; n < AES_BLOCK_SIZE ; ++n)
+               ivec[n] = ovec[n+num]<<rem | ovec[n+num+1]>>(8-rem);
+
+    /* it is not necessary to cleanse ovec, since the IV is not secret */
+    }
+
+/* N.B. This expects the input to be packed, MS bit first */
+void AES_cfb1_encrypt(const unsigned char *in, unsigned char *out,
+                     const unsigned long length, const AES_KEY *key,
+                     unsigned char *ivec, int *num, const int enc)
+    {
+    unsigned int n;
+    unsigned char c[1],d[1];
+
+    assert(in && out && key && ivec && num);
+    assert(*num == 0);
+
+    memset(out,0,(length+7)/8);
+    for(n=0 ; n < length ; ++n)
+       {
+       c[0]=(in[n/8]&(1 << (7-n%8))) ? 0x80 : 0;
+       AES_cfbr_encrypt_block(c,d,1,key,ivec,enc);
+       out[n/8]=(out[n/8]&~(1 << (7-n%8)))|((d[0]&0x80) >> (n%8));
+       }
+    }
+
+void AES_cfb8_encrypt(const unsigned char *in, unsigned char *out,
+                     const unsigned long length, const AES_KEY *key,
+                     unsigned char *ivec, int *num, const int enc)
+    {
+    unsigned int n;
+
+    assert(in && out && key && ivec && num);
+    assert(*num == 0);
+
+    for(n=0 ; n < length ; ++n)
+       AES_cfbr_encrypt_block(&in[n],&out[n],8,key,ivec,enc);
+    }
+