SHA-1/SSSE3: Improve performance on large buffers
[libgcrypt.git] / cipher / cast5.c
index 4377c28..115e1e6 100644 (file)
@@ -42,6 +42,7 @@
 #include "g10lib.h"
 #include "types.h"
 #include "cipher.h"
+#include "bithelp.h"
 #include "bufhelp.h"
 #include "cipher-selftest.h"
 
 # define USE_AMD64_ASM 1
 #endif
 
-/* USE_ARMV6_ASM indicates whether to use ARMv6 assembly code. */
-#undef USE_ARMV6_ASM
-#if defined(HAVE_ARM_ARCH_V6) && defined(__ARMEL__)
+/* USE_ARM_ASM indicates whether to use ARM assembly code. */
+#undef USE_ARM_ASM
+#if defined(__ARMEL__)
 # ifdef HAVE_COMPATIBLE_GCC_ARM_PLATFORM_AS
-#  define USE_ARMV6_ASM 1
+#  define USE_ARM_ASM 1
 # endif
 #endif
 
 typedef struct {
     u32  Km[16];
     byte Kr[16];
-#ifdef USE_ARMV6_ASM
+#ifdef USE_ARM_ASM
     u32 Kr_arm_enc[16 / sizeof(u32)];
     u32 Kr_arm_dec[16 / sizeof(u32)];
 #endif
 } CAST5_context;
 
 static gcry_err_code_t cast_setkey (void *c, const byte *key, unsigned keylen);
-static void encrypt_block (void *c, byte *outbuf, const byte *inbuf);
-static void decrypt_block (void *c, byte *outbuf, const byte *inbuf);
+static unsigned int encrypt_block (void *c, byte *outbuf, const byte *inbuf);
+static unsigned int decrypt_block (void *c, byte *outbuf, const byte *inbuf);
 
 
 
@@ -383,86 +384,76 @@ do_decrypt_block (CAST5_context *context, byte *outbuf, const byte *inbuf)
   _gcry_cast5_amd64_decrypt_block (context, outbuf, inbuf);
 }
 
-static void encrypt_block (void *context , byte *outbuf, const byte *inbuf)
+static unsigned int
+encrypt_block (void *context , byte *outbuf, const byte *inbuf)
 {
   CAST5_context *c = (CAST5_context *) context;
   do_encrypt_block (c, outbuf, inbuf);
-  _gcry_burn_stack (2*8);
+  return /*burn_stack*/ (2*8);
 }
 
-static void decrypt_block (void *context, byte *outbuf, const byte *inbuf)
+static unsigned int
+decrypt_block (void *context, byte *outbuf, const byte *inbuf)
 {
   CAST5_context *c = (CAST5_context *) context;
   _gcry_cast5_amd64_decrypt_block (c, outbuf, inbuf);
-  _gcry_burn_stack (2*8);
+  return /*burn_stack*/ (2*8);
 }
 
-#elif defined(USE_ARMV6_ASM)
+#elif defined(USE_ARM_ASM)
 
-/* ARMv6 assembly implementations of CAST5. */
-extern void _gcry_cast5_armv6_encrypt_block(CAST5_context *c, byte *outbuf,
+/* ARM assembly implementations of CAST5. */
+extern void _gcry_cast5_arm_encrypt_block(CAST5_context *c, byte *outbuf,
                                            const byte *inbuf);
 
-extern void _gcry_cast5_armv6_decrypt_block(CAST5_context *c, byte *outbuf,
+extern void _gcry_cast5_arm_decrypt_block(CAST5_context *c, byte *outbuf,
                                            const byte *inbuf);
 
 /* These assembly implementations process two blocks in parallel. */
-extern void _gcry_cast5_armv6_ctr_enc(CAST5_context *ctx, byte *out,
+extern void _gcry_cast5_arm_ctr_enc(CAST5_context *ctx, byte *out,
                                      const byte *in, byte *ctr);
 
-extern void _gcry_cast5_armv6_cbc_dec(CAST5_context *ctx, byte *out,
+extern void _gcry_cast5_arm_cbc_dec(CAST5_context *ctx, byte *out,
                                      const byte *in, byte *iv);
 
-extern void _gcry_cast5_armv6_cfb_dec(CAST5_context *ctx, byte *out,
+extern void _gcry_cast5_arm_cfb_dec(CAST5_context *ctx, byte *out,
                                      const byte *in, byte *iv);
 
 static void
 do_encrypt_block (CAST5_context *context, byte *outbuf, const byte *inbuf)
 {
-  _gcry_cast5_armv6_encrypt_block (context, outbuf, inbuf);
+  _gcry_cast5_arm_encrypt_block (context, outbuf, inbuf);
 }
 
 static void
 do_decrypt_block (CAST5_context *context, byte *outbuf, const byte *inbuf)
 {
-  _gcry_cast5_armv6_decrypt_block (context, outbuf, inbuf);
+  _gcry_cast5_arm_decrypt_block (context, outbuf, inbuf);
 }
 
-static void encrypt_block (void *context , byte *outbuf, const byte *inbuf)
+static unsigned int
+encrypt_block (void *context , byte *outbuf, const byte *inbuf)
 {
   CAST5_context *c = (CAST5_context *) context;
   do_encrypt_block (c, outbuf, inbuf);
-  _gcry_burn_stack (10*4);
+  return /*burn_stack*/ (10*4);
 }
 
-static void decrypt_block (void *context, byte *outbuf, const byte *inbuf)
+static unsigned int
+decrypt_block (void *context, byte *outbuf, const byte *inbuf)
 {
   CAST5_context *c = (CAST5_context *) context;
   do_decrypt_block (c, outbuf, inbuf);
-  _gcry_burn_stack (10*4);
+  return /*burn_stack*/ (10*4);
 }
 
-#else /*USE_ARMV6_ASM*/
+#else /*USE_ARM_ASM*/
 
-#if defined(__GNUC__) && defined(__i386__)
-static inline u32
-rol(int n, u32 x)
-{
-       __asm__("roll %%cl,%0"
-               :"=r" (x)
-               :"0" (x),"c" (n)
-               :"cc");
-       return x;
-}
-#else
-#define rol(n,x) ( ((x) << (n)) | ((x) >> (32-(n))) )
-#endif
-
-#define F1(D,m,r)  (  (I = ((m) + (D))), (I=rol((r),I)),   \
+#define F1(D,m,r)  (  (I = ((m) + (D))), (I=rol(I,(r))),   \
     (((s1[I >> 24] ^ s2[(I>>16)&0xff]) - s3[(I>>8)&0xff]) + s4[I&0xff]) )
-#define F2(D,m,r)  (  (I = ((m) ^ (D))), (I=rol((r),I)),   \
+#define F2(D,m,r)  (  (I = ((m) ^ (D))), (I=rol(I,(r))),   \
     (((s1[I >> 24] - s2[(I>>16)&0xff]) + s3[(I>>8)&0xff]) ^ s4[I&0xff]) )
-#define F3(D,m,r)  (  (I = ((m) - (D))), (I=rol((r),I)),   \
+#define F3(D,m,r)  (  (I = ((m) - (D))), (I=rol(I,(r))),   \
     (((s1[I >> 24] + s2[(I>>16)&0xff]) ^ s3[(I>>8)&0xff]) - s4[I&0xff]) )
 
 static void
@@ -479,8 +470,8 @@ do_encrypt_block( CAST5_context *c, byte *outbuf, const byte *inbuf )
     /* (L0,R0) <-- (m1...m64). (Split the plaintext into left and
      * right 32-bit halves L0 = m1...m32 and R0 = m33...m64.)
      */
-    l = inbuf[0] << 24 | inbuf[1] << 16 | inbuf[2] << 8 | inbuf[3];
-    r = inbuf[4] << 24 | inbuf[5] << 16 | inbuf[6] << 8 | inbuf[7];
+    l = buf_get_be32(inbuf + 0);
+    r = buf_get_be32(inbuf + 4);
 
     /* (16 rounds) for i from 1 to 16, compute Li and Ri as follows:
      * Li = Ri-1;
@@ -509,22 +500,16 @@ do_encrypt_block( CAST5_context *c, byte *outbuf, const byte *inbuf )
 
     /* c1...c64 <-- (R16,L16). (Exchange final blocks L16, R16 and
      * concatenate to form the ciphertext.) */
-    outbuf[0] = (r >> 24) & 0xff;
-    outbuf[1] = (r >> 16) & 0xff;
-    outbuf[2] = (r >>  8) & 0xff;
-    outbuf[3] =  r       & 0xff;
-    outbuf[4] = (l >> 24) & 0xff;
-    outbuf[5] = (l >> 16) & 0xff;
-    outbuf[6] = (l >>  8) & 0xff;
-    outbuf[7] =  l       & 0xff;
+    buf_put_be32(outbuf + 0, r);
+    buf_put_be32(outbuf + 4, l);
 }
 
-static void
+static unsigned int
 encrypt_block (void *context , byte *outbuf, const byte *inbuf)
 {
   CAST5_context *c = (CAST5_context *) context;
   do_encrypt_block (c, outbuf, inbuf);
-  _gcry_burn_stack (20+4*sizeof(void*));
+  return /*burn_stack*/ (20+4*sizeof(void*));
 }
 
 
@@ -539,8 +524,8 @@ do_decrypt_block (CAST5_context *c, byte *outbuf, const byte *inbuf )
     Km = c->Km;
     Kr = c->Kr;
 
-    l = inbuf[0] << 24 | inbuf[1] << 16 | inbuf[2] << 8 | inbuf[3];
-    r = inbuf[4] << 24 | inbuf[5] << 16 | inbuf[6] << 8 | inbuf[7];
+    l = buf_get_be32(inbuf + 0);
+    r = buf_get_be32(inbuf + 4);
 
     t = l; l = r; r = t ^ F1(r, Km[15], Kr[15]);
     t = l; l = r; r = t ^ F3(r, Km[14], Kr[14]);
@@ -559,25 +544,19 @@ do_decrypt_block (CAST5_context *c, byte *outbuf, const byte *inbuf )
     t = l; l = r; r = t ^ F2(r, Km[ 1], Kr[ 1]);
     t = l; l = r; r = t ^ F1(r, Km[ 0], Kr[ 0]);
 
-    outbuf[0] = (r >> 24) & 0xff;
-    outbuf[1] = (r >> 16) & 0xff;
-    outbuf[2] = (r >>  8) & 0xff;
-    outbuf[3] =  r       & 0xff;
-    outbuf[4] = (l >> 24) & 0xff;
-    outbuf[5] = (l >> 16) & 0xff;
-    outbuf[6] = (l >>  8) & 0xff;
-    outbuf[7] =  l       & 0xff;
+    buf_put_be32(outbuf + 0, r);
+    buf_put_be32(outbuf + 4, l);
 }
 
-static void
+static unsigned int
 decrypt_block (void *context, byte *outbuf, const byte *inbuf)
 {
   CAST5_context *c = (CAST5_context *) context;
   do_decrypt_block (c, outbuf, inbuf);
-  _gcry_burn_stack (20+4*sizeof(void*));
+  return /*burn_stack*/ (20+4*sizeof(void*));
 }
 
-#endif /*!USE_ARMV6_ASM*/
+#endif /*!USE_ARM_ASM*/
 
 
 /* Bulk encryption of complete blocks in CTR mode.  This function is only
@@ -585,7 +564,7 @@ decrypt_block (void *context, byte *outbuf, const byte *inbuf)
    of size CAST5_BLOCKSIZE. */
 void
 _gcry_cast5_ctr_enc(void *context, unsigned char *ctr, void *outbuf_arg,
-                   const void *inbuf_arg, unsigned int nblocks)
+                   const void *inbuf_arg, size_t nblocks)
 {
   CAST5_context *ctx = context;
   unsigned char *outbuf = outbuf_arg;
@@ -613,12 +592,12 @@ _gcry_cast5_ctr_enc(void *context, unsigned char *ctr, void *outbuf_arg,
     /* Use generic code to handle smaller chunks... */
     /* TODO: use caching instead? */
   }
-#elif defined(USE_ARMV6_ASM)
+#elif defined(USE_ARM_ASM)
   {
     /* Process data in 2 block chunks. */
     while (nblocks >= 2)
       {
-        _gcry_cast5_armv6_ctr_enc(ctx, outbuf, inbuf, ctr);
+        _gcry_cast5_arm_ctr_enc(ctx, outbuf, inbuf, ctr);
 
         nblocks -= 2;
         outbuf += 2 * CAST5_BLOCKSIZE;
@@ -656,7 +635,7 @@ _gcry_cast5_ctr_enc(void *context, unsigned char *ctr, void *outbuf_arg,
    intended for the bulk encryption feature of cipher.c. */
 void
 _gcry_cast5_cbc_dec(void *context, unsigned char *iv, void *outbuf_arg,
-                   const void *inbuf_arg, unsigned int nblocks)
+                   const void *inbuf_arg, size_t nblocks)
 {
   CAST5_context *ctx = context;
   unsigned char *outbuf = outbuf_arg;
@@ -681,12 +660,12 @@ _gcry_cast5_cbc_dec(void *context, unsigned char *iv, void *outbuf_arg,
 
     /* Use generic code to handle smaller chunks... */
   }
-#elif defined(USE_ARMV6_ASM)
+#elif defined(USE_ARM_ASM)
   {
     /* Process data in 2 block chunks. */
     while (nblocks >= 2)
       {
-        _gcry_cast5_armv6_cbc_dec(ctx, outbuf, inbuf, iv);
+        _gcry_cast5_arm_cbc_dec(ctx, outbuf, inbuf, iv);
 
         nblocks -= 2;
         outbuf += 2 * CAST5_BLOCKSIZE;
@@ -699,14 +678,11 @@ _gcry_cast5_cbc_dec(void *context, unsigned char *iv, void *outbuf_arg,
 
   for ( ;nblocks; nblocks-- )
     {
-      /* We need to save INBUF away because it may be identical to
-         OUTBUF.  */
-      memcpy(savebuf, inbuf, CAST5_BLOCKSIZE);
-
-      do_decrypt_block (ctx, outbuf, inbuf);
+      /* INBUF is needed later and it may be identical to OUTBUF, so store
+         the intermediate result to SAVEBUF.  */
+      do_decrypt_block (ctx, savebuf, inbuf);
 
-      buf_xor(outbuf, outbuf, iv, CAST5_BLOCKSIZE);
-      memcpy(iv, savebuf, CAST5_BLOCKSIZE);
+      buf_xor_n_copy_2(outbuf, savebuf, iv, inbuf, CAST5_BLOCKSIZE);
       inbuf += CAST5_BLOCKSIZE;
       outbuf += CAST5_BLOCKSIZE;
     }
@@ -719,7 +695,7 @@ _gcry_cast5_cbc_dec(void *context, unsigned char *iv, void *outbuf_arg,
    intended for the bulk encryption feature of cipher.c. */
 void
 _gcry_cast5_cfb_dec(void *context, unsigned char *iv, void *outbuf_arg,
-                   const void *inbuf_arg, unsigned int nblocks)
+                   const void *inbuf_arg, size_t nblocks)
 {
   CAST5_context *ctx = context;
   unsigned char *outbuf = outbuf_arg;
@@ -743,12 +719,12 @@ _gcry_cast5_cfb_dec(void *context, unsigned char *iv, void *outbuf_arg,
 
     /* Use generic code to handle smaller chunks... */
   }
-#elif defined(USE_ARMV6_ASM)
+#elif defined(USE_ARM_ASM)
   {
     /* Process data in 2 block chunks. */
     while (nblocks >= 2)
       {
-        _gcry_cast5_armv6_cfb_dec(ctx, outbuf, inbuf, iv);
+        _gcry_cast5_arm_cfb_dec(ctx, outbuf, inbuf, iv);
 
         nblocks -= 2;
         outbuf += 2 * CAST5_BLOCKSIZE;
@@ -820,10 +796,13 @@ static const char*
 selftest(void)
 {
     CAST5_context c;
-    byte key[16]  = { 0x01, 0x23, 0x45, 0x67, 0x12, 0x34, 0x56, 0x78,
+    static const byte key[16] =
+                    { 0x01, 0x23, 0x45, 0x67, 0x12, 0x34, 0x56, 0x78,
                      0x23, 0x45, 0x67, 0x89, 0x34, 0x56, 0x78, 0x9A  };
-    byte plain[8] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF };
-    byte cipher[8]= { 0x23, 0x8B, 0x4F, 0xE5, 0x84, 0x7E, 0x44, 0xB2 };
+    static const byte plain[8] =
+                    { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF };
+    static const byte cipher[8] =
+                    { 0x23, 0x8B, 0x4F, 0xE5, 0x84, 0x7E, 0x44, 0xB2 };
     byte buffer[8];
     const char *r;
 
@@ -945,10 +924,10 @@ do_cast_setkey( CAST5_context *c, const byte *key, unsigned keylen )
   if( keylen != 16 )
     return GPG_ERR_INV_KEYLEN;
 
-  x[0] = key[0]  << 24 | key[1]  << 16 | key[2]  << 8 | key[3];
-  x[1] = key[4]  << 24 | key[5]  << 16 | key[6]  << 8 | key[7];
-  x[2] = key[8]  << 24 | key[9]  << 16 | key[10] << 8 | key[11];
-  x[3] = key[12] << 24 | key[13] << 16 | key[14] << 8 | key[15];
+  x[0] = buf_get_be32(key + 0);
+  x[1] = buf_get_be32(key + 4);
+  x[2] = buf_get_be32(key + 8);
+  x[3] = buf_get_be32(key + 12);
 
   key_schedule( x, z, k );
   for(i=0; i < 16; i++ )
@@ -957,7 +936,7 @@ do_cast_setkey( CAST5_context *c, const byte *key, unsigned keylen )
   for(i=0; i < 16; i++ )
     c->Kr[i] = k[i] & 0x1f;
 
-#ifdef USE_ARMV6_ASM
+#ifdef USE_ARM_ASM
   for (i = 0; i < 4; i++)
     {
       byte Kr_arm[4];
@@ -983,9 +962,9 @@ do_cast_setkey( CAST5_context *c, const byte *key, unsigned keylen )
     }
 #endif
 
-  memset(&x,0, sizeof x);
-  memset(&z,0, sizeof z);
-  memset(&k,0, sizeof k);
+  wipememory(x, sizeof x);
+  wipememory(z, sizeof z);
+  wipememory(k, sizeof k);
 
 #undef xi
 #undef zi
@@ -997,13 +976,13 @@ cast_setkey (void *context, const byte *key, unsigned keylen )
 {
   CAST5_context *c = (CAST5_context *) context;
   gcry_err_code_t rc = do_cast_setkey (c, key, keylen);
-  _gcry_burn_stack (96+7*sizeof(void*));
   return rc;
 }
 
 
 gcry_cipher_spec_t _gcry_cipher_spec_cast5 =
   {
+    GCRY_CIPHER_CAST5, {0, 0},
     "CAST5", NULL, NULL, CAST5_BLOCKSIZE, 128, sizeof (CAST5_context),
     cast_setkey, encrypt_block, decrypt_block
   };