Add ARMv8/CE acceleration for AES-XTS
[libgcrypt.git] / cipher / cipher-cfb.c
index f4152b9..c888e70 100644 (file)
 
 #include "g10lib.h"
 #include "cipher.h"
-#include "ath.h"
+#include "bufhelp.h"
 #include "./cipher-internal.h"
 
 
 gcry_err_code_t
 _gcry_cipher_cfb_encrypt (gcry_cipher_hd_t c,
-                          unsigned char *outbuf, unsigned int outbuflen,
-                          const unsigned char *inbuf, unsigned int inbuflen)
+                          unsigned char *outbuf, size_t outbuflen,
+                          const unsigned char *inbuf, size_t inbuflen)
 {
   unsigned char *ivp;
-  size_t blocksize = c->cipher->blocksize;
+  gcry_cipher_encrypt_t enc_fn = c->spec->encrypt;
+  size_t blocksize = c->spec->blocksize;
   size_t blocksize_x_2 = blocksize + blocksize;
+  unsigned int burn, nburn;
+
+  /* Tell compiler that we require a cipher with a 64bit or 128 bit block
+   * length, to allow better optimization of this function.  */
+  if (blocksize > 16 || blocksize < 8 || blocksize & (8 - 1))
+    return GPG_ERR_INV_LENGTH;
 
   if (outbuflen < inbuflen)
     return GPG_ERR_BUFFER_TOO_SHORT;
@@ -46,19 +53,23 @@ _gcry_cipher_cfb_encrypt (gcry_cipher_hd_t c,
     {
       /* Short enough to be encoded by the remaining XOR mask. */
       /* XOR the input with the IV and store input into IV. */
-      for (ivp=c->u_iv.iv+c->cipher->blocksize - c->unused;
-           inbuflen;
-           inbuflen--, c->unused-- )
-        *outbuf++ = (*ivp++ ^= *inbuf++);
+      ivp = c->u_iv.iv + blocksize - c->unused;
+      buf_xor_2dst(outbuf, ivp, inbuf, inbuflen);
+      c->unused -= inbuflen;
       return 0;
     }
 
+  burn = 0;
+
   if ( c->unused )
     {
       /* XOR the input with the IV and store input into IV */
       inbuflen -= c->unused;
-      for(ivp=c->u_iv.iv+blocksize - c->unused; c->unused; c->unused-- )
-        *outbuf++ = (*ivp++ ^= *inbuf++);
+      ivp = c->u_iv.iv + blocksize - c->unused;
+      buf_xor_2dst(outbuf, ivp, inbuf, c->unused);
+      outbuf += c->unused;
+      inbuf += c->unused;
+      c->unused = 0;
     }
 
   /* Now we can process complete blocks.  We use a loop as long as we
@@ -66,7 +77,7 @@ _gcry_cipher_cfb_encrypt (gcry_cipher_hd_t c,
      also allows to use a bulk encryption function if available.  */
   if (inbuflen >= blocksize_x_2 && c->bulk.cfb_enc)
     {
-      unsigned int nblocks = inbuflen / blocksize;
+      size_t nblocks = inbuflen / blocksize;
       c->bulk.cfb_enc (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks);
       outbuf += nblocks * blocksize;
       inbuf  += nblocks * blocksize;
@@ -76,52 +87,66 @@ _gcry_cipher_cfb_encrypt (gcry_cipher_hd_t c,
     {
       while ( inbuflen >= blocksize_x_2 )
         {
-          int i;
           /* Encrypt the IV. */
-          c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
+          nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
+          burn = nburn > burn ? nburn : burn;
           /* XOR the input with the IV and store input into IV.  */
-          for(ivp=c->u_iv.iv,i=0; i < blocksize; i++ )
-            *outbuf++ = (*ivp++ ^= *inbuf++);
+          buf_xor_2dst(outbuf, c->u_iv.iv, inbuf, blocksize);
+          outbuf += blocksize;
+          inbuf += blocksize;
           inbuflen -= blocksize;
         }
     }
 
   if ( inbuflen >= blocksize )
     {
-      int i;
       /* Save the current IV and then encrypt the IV. */
-      memcpy( c->lastiv, c->u_iv.iv, blocksize );
-      c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
+      buf_cpy( c->lastiv, c->u_iv.iv, blocksize );
+      nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
+      burn = nburn > burn ? nburn : burn;
       /* XOR the input with the IV and store input into IV */
-      for(ivp=c->u_iv.iv,i=0; i < blocksize; i++ )
-        *outbuf++ = (*ivp++ ^= *inbuf++);
+      buf_xor_2dst(outbuf, c->u_iv.iv, inbuf, blocksize);
+      outbuf += blocksize;
+      inbuf += blocksize;
       inbuflen -= blocksize;
     }
   if ( inbuflen )
     {
       /* Save the current IV and then encrypt the IV. */
-      memcpy( c->lastiv, c->u_iv.iv, blocksize );
-      c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
+      buf_cpy( c->lastiv, c->u_iv.iv, blocksize );
+      nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
+      burn = nburn > burn ? nburn : burn;
       c->unused = blocksize;
       /* Apply the XOR. */
       c->unused -= inbuflen;
-      for(ivp=c->u_iv.iv; inbuflen; inbuflen-- )
-        *outbuf++ = (*ivp++ ^= *inbuf++);
+      buf_xor_2dst(outbuf, c->u_iv.iv, inbuf, inbuflen);
+      outbuf += inbuflen;
+      inbuf += inbuflen;
+      inbuflen = 0;
     }
+
+  if (burn > 0)
+    _gcry_burn_stack (burn + 4 * sizeof(void *));
+
   return 0;
 }
 
 
 gcry_err_code_t
 _gcry_cipher_cfb_decrypt (gcry_cipher_hd_t c,
-                          unsigned char *outbuf, unsigned int outbuflen,
-                          const unsigned char *inbuf, unsigned int inbuflen)
+                          unsigned char *outbuf, size_t outbuflen,
+                          const unsigned char *inbuf, size_t inbuflen)
 {
   unsigned char *ivp;
-  unsigned long temp;
-  int i;
-  size_t blocksize = c->cipher->blocksize;
+  gcry_cipher_encrypt_t enc_fn = c->spec->encrypt;
+  size_t blocksize = c->spec->blocksize;
   size_t blocksize_x_2 = blocksize + blocksize;
+  unsigned int burn, nburn;
+
+  /* Tell compiler that we require a cipher with a 64bit or 128 bit block
+   * length, to allow better optimization of this function.  */
+  if (blocksize > 16 || blocksize < 8 || blocksize & (8 - 1))
+    return GPG_ERR_INV_LENGTH;
 
   if (outbuflen < inbuflen)
     return GPG_ERR_BUFFER_TOO_SHORT;
@@ -130,27 +155,23 @@ _gcry_cipher_cfb_decrypt (gcry_cipher_hd_t c,
     {
       /* Short enough to be encoded by the remaining XOR mask. */
       /* XOR the input with the IV and store input into IV. */
-      for (ivp=c->u_iv.iv+blocksize - c->unused;
-           inbuflen;
-           inbuflen--, c->unused--)
-        {
-          temp = *inbuf++;
-          *outbuf++ = *ivp ^ temp;
-          *ivp++ = temp;
-        }
+      ivp = c->u_iv.iv + blocksize - c->unused;
+      buf_xor_n_copy(outbuf, ivp, inbuf, inbuflen);
+      c->unused -= inbuflen;
       return 0;
     }
 
+  burn = 0;
+
   if (c->unused)
     {
       /* XOR the input with the IV and store input into IV. */
       inbuflen -= c->unused;
-      for (ivp=c->u_iv.iv+blocksize - c->unused; c->unused; c->unused-- )
-        {
-          temp = *inbuf++;
-          *outbuf++ = *ivp ^ temp;
-          *ivp++ = temp;
-        }
+      ivp = c->u_iv.iv + blocksize - c->unused;
+      buf_xor_n_copy(outbuf, ivp, inbuf, c->unused);
+      outbuf += c->unused;
+      inbuf += c->unused;
+      c->unused = 0;
     }
 
   /* Now we can process complete blocks.  We use a loop as long as we
@@ -158,7 +179,7 @@ _gcry_cipher_cfb_decrypt (gcry_cipher_hd_t c,
      also allows to use a bulk encryption function if available.  */
   if (inbuflen >= blocksize_x_2 && c->bulk.cfb_dec)
     {
-      unsigned int nblocks = inbuflen / blocksize;
+      size_t nblocks = inbuflen / blocksize;
       c->bulk.cfb_dec (&c->context.c, c->u_iv.iv, outbuf, inbuf, nblocks);
       outbuf += nblocks * blocksize;
       inbuf  += nblocks * blocksize;
@@ -169,14 +190,12 @@ _gcry_cipher_cfb_decrypt (gcry_cipher_hd_t c,
       while (inbuflen >= blocksize_x_2 )
         {
           /* Encrypt the IV. */
-          c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
+          nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
+          burn = nburn > burn ? nburn : burn;
           /* XOR the input with the IV and store input into IV. */
-          for (ivp=c->u_iv.iv,i=0; i < blocksize; i++ )
-            {
-              temp = *inbuf++;
-              *outbuf++ = *ivp ^ temp;
-              *ivp++ = temp;
-            }
+          buf_xor_n_copy(outbuf, c->u_iv.iv, inbuf, blocksize);
+          outbuf += blocksize;
+          inbuf += blocksize;
           inbuflen -= blocksize;
         }
     }
@@ -184,32 +203,123 @@ _gcry_cipher_cfb_decrypt (gcry_cipher_hd_t c,
   if (inbuflen >= blocksize )
     {
       /* Save the current IV and then encrypt the IV. */
-      memcpy ( c->lastiv, c->u_iv.iv, blocksize);
-      c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
+      buf_cpy ( c->lastiv, c->u_iv.iv, blocksize);
+      nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
+      burn = nburn > burn ? nburn : burn;
       /* XOR the input with the IV and store input into IV */
-      for (ivp=c->u_iv.iv,i=0; i < blocksize; i++ )
-        {
-          temp = *inbuf++;
-          *outbuf++ = *ivp ^ temp;
-          *ivp++ = temp;
-        }
+      buf_xor_n_copy(outbuf, c->u_iv.iv, inbuf, blocksize);
+      outbuf += blocksize;
+      inbuf += blocksize;
       inbuflen -= blocksize;
     }
 
   if (inbuflen)
     {
       /* Save the current IV and then encrypt the IV. */
-      memcpy ( c->lastiv, c->u_iv.iv, blocksize );
-      c->cipher->encrypt ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
+      buf_cpy ( c->lastiv, c->u_iv.iv, blocksize );
+      nburn = enc_fn ( &c->context.c, c->u_iv.iv, c->u_iv.iv );
+      burn = nburn > burn ? nburn : burn;
       c->unused = blocksize;
       /* Apply the XOR. */
       c->unused -= inbuflen;
-      for (ivp=c->u_iv.iv; inbuflen; inbuflen-- )
-        {
-          temp = *inbuf++;
-          *outbuf++ = *ivp ^ temp;
-          *ivp++ = temp;
-        }
+      buf_xor_n_copy(outbuf, c->u_iv.iv, inbuf, inbuflen);
+      outbuf += inbuflen;
+      inbuf += inbuflen;
+      inbuflen = 0;
+    }
+
+  if (burn > 0)
+    _gcry_burn_stack (burn + 4 * sizeof(void *));
+
+  return 0;
+}
+
+
+gcry_err_code_t
+_gcry_cipher_cfb8_encrypt (gcry_cipher_hd_t c,
+                          unsigned char *outbuf, size_t outbuflen,
+                          const unsigned char *inbuf, size_t inbuflen)
+{
+  gcry_cipher_encrypt_t enc_fn = c->spec->encrypt;
+  size_t blocksize = c->spec->blocksize;
+  unsigned int burn, nburn;
+
+  if (outbuflen < inbuflen)
+    return GPG_ERR_BUFFER_TOO_SHORT;
+
+  burn = 0;
+
+  while ( inbuflen > 0)
+    {
+      int i;
+
+      /* Encrypt the IV. */
+      nburn = enc_fn ( &c->context.c, c->lastiv, c->u_iv.iv );
+      burn = nburn > burn ? nburn : burn;
+
+      outbuf[0] = c->lastiv[0] ^ inbuf[0];
+
+      /* Bitshift iv by 8 bit to the left */
+      for (i = 0; i < blocksize-1; i++)
+        c->u_iv.iv[i] = c->u_iv.iv[i+1];
+
+      /* append cipher text to iv */
+      c->u_iv.iv[blocksize-1] = outbuf[0];
+
+      outbuf += 1;
+      inbuf += 1;
+      inbuflen -= 1;
     }
+
+  if (burn > 0)
+    _gcry_burn_stack (burn + 4 * sizeof(void *));
+
+  return 0;
+}
+
+
+gcry_err_code_t
+_gcry_cipher_cfb8_decrypt (gcry_cipher_hd_t c,
+                          unsigned char *outbuf, size_t outbuflen,
+                          const unsigned char *inbuf, size_t inbuflen)
+{
+  gcry_cipher_encrypt_t enc_fn = c->spec->encrypt;
+  size_t blocksize = c->spec->blocksize;
+  unsigned int burn, nburn;
+  unsigned char appendee;
+
+  if (outbuflen < inbuflen)
+    return GPG_ERR_BUFFER_TOO_SHORT;
+
+  burn = 0;
+
+  while (inbuflen > 0)
+    {
+      int i;
+
+      /* Encrypt the IV. */
+      nburn = enc_fn ( &c->context.c, c->lastiv, c->u_iv.iv );
+      burn = nburn > burn ? nburn : burn;
+
+      /* inbuf might == outbuf, make sure we keep the value
+         so we can append it later */
+      appendee = inbuf[0];
+
+      outbuf[0] = inbuf[0] ^ c->lastiv[0];
+
+      /* Bitshift iv by 8 bit to the left */
+      for (i = 0; i < blocksize-1; i++)
+        c->u_iv.iv[i] = c->u_iv.iv[i+1];
+
+      c->u_iv.iv[blocksize-1] = appendee;
+
+      outbuf += 1;
+      inbuf += 1;
+      inbuflen -= 1;
+    }
+
+  if (burn > 0)
+    _gcry_burn_stack (burn + 4 * sizeof(void *));
+
   return 0;
 }