Fix Serpent-AVX2 and Camellia-AVX2 counter modes
authorJussi Kivilinna <jussi.kivilinna@iki.fi>
Sat, 9 Nov 2013 20:39:19 +0000 (22:39 +0200)
committerJussi Kivilinna <jussi.kivilinna@iki.fi>
Sat, 9 Nov 2013 20:39:19 +0000 (22:39 +0200)
* cipher/camellia-aesni-avx2-amd64.S
(_gcry_camellia_aesni_avx2_ctr_enc): Byte-swap before checking for
overflow handling.
* cipher/camellia-glue.c (selftest_ctr_128, selftest_cfb_128)
(selftest_cbc_128): Add 16 to nblocks.
* cipher/cipher-selftest.c (_gcry_selftest_helper_ctr): Add test with
non-overflowing IV and modify overflow IV to detect broken endianness
handling.
* cipher/serpent-avx2-amd64.S (_gcry_serpent_avx2_ctr_enc): Byte-swap
before checking for overflow handling; Fix crazy-mixed-endian IV
construction to big-endian.
* cipher/serpent.c (selftest_ctr_128, selftest_cfb_128)
(selftest_cbc_128): Add 8 to nblocks.
--

The selftest for CTR was setting counter-IV to all '0xff' except last byte.
This had the effect that even with broken endianness handling Serpent-AVX2 and
Camellia-AVX2 passed the tests.

Patch corrects the CTR selftest and fixes the broken implementations.

Signed-off-by: Jussi Kivilinna <jussi.kivilinna@iki.fi>
cipher/camellia-aesni-avx2-amd64.S
cipher/camellia-glue.c
cipher/cipher-selftest.c
cipher/serpent-avx2-amd64.S
cipher/serpent.c

index f0a4fd8..78ef2d6 100644 (file)
@@ -937,6 +937,9 @@ _gcry_camellia_aesni_avx2_ctr_enc:
         *      %rcx: iv (big endian, 128bit)
         */
 
+       movq 8(%rcx), %r11;
+       bswapq %r11;
+
        vzeroupper;
 
        movq %rsp, %r10;
@@ -958,7 +961,7 @@ _gcry_camellia_aesni_avx2_ctr_enc:
        vmovdqa %ymm13, 15 * 32(%rax);
 
        /* check need for handling 64-bit overflow and carry */
-       cmpq $(0xffffffffffffffff - 32), (%rcx);
+       cmpq $(0xffffffffffffffff - 32), %r11;
        ja .Lload_ctr_carry;
 
        /* construct IVs */
index 42b62d2..b7ae0fc 100644 (file)
@@ -537,7 +537,7 @@ _gcry_camellia_cfb_dec(void *context, unsigned char *iv,
 static const char*
 selftest_ctr_128 (void)
 {
-  const int nblocks = 32+1;
+  const int nblocks = 32+16+1;
   const int blocksize = CAMELLIA_BLOCK_SIZE;
   const int context_size = sizeof(CAMELLIA_context);
 
@@ -551,7 +551,7 @@ selftest_ctr_128 (void)
 static const char*
 selftest_cbc_128 (void)
 {
-  const int nblocks = 32+2;
+  const int nblocks = 32+16+2;
   const int blocksize = CAMELLIA_BLOCK_SIZE;
   const int context_size = sizeof(CAMELLIA_context);
 
@@ -565,7 +565,7 @@ selftest_cbc_128 (void)
 static const char*
 selftest_cfb_128 (void)
 {
-  const int nblocks = 32+2;
+  const int nblocks = 32+16+2;
   const int blocksize = CAMELLIA_BLOCK_SIZE;
   const int context_size = sizeof(CAMELLIA_context);
 
index 17742e3..8e58150 100644 (file)
@@ -286,7 +286,8 @@ _gcry_selftest_helper_ctr (const char *cipher, gcry_cipher_setkey_t setkey_func,
                           const int context_size)
 {
   int i, j, offs, diff;
-  unsigned char *ctx, *plaintext, *plaintext2, *ciphertext, *iv, *iv2, *mem;
+  unsigned char *ctx, *plaintext, *plaintext2, *ciphertext, *ciphertext2,
+                *iv, *iv2, *mem;
   unsigned int ctx_aligned_size, memsize;
 
   static const unsigned char key[16] ATTR_ALIGNED_16 = {
@@ -299,7 +300,7 @@ _gcry_selftest_helper_ctr (const char *cipher, gcry_cipher_setkey_t setkey_func,
   ctx_aligned_size = context_size + 15;
   ctx_aligned_size -= ctx_aligned_size & 0xf;
 
-  memsize = ctx_aligned_size + (blocksize * 2) + (blocksize * nblocks * 3) + 16;
+  memsize = ctx_aligned_size + (blocksize * 2) + (blocksize * nblocks * 4) + 16;
 
   mem = gcry_calloc (1, memsize);
   if (!mem)
@@ -312,6 +313,7 @@ _gcry_selftest_helper_ctr (const char *cipher, gcry_cipher_setkey_t setkey_func,
   plaintext = iv2 + blocksize;
   plaintext2 = plaintext + nblocks * blocksize;
   ciphertext = plaintext2 + nblocks * blocksize;
+  ciphertext2 = ciphertext + nblocks * blocksize;
 
   /* Initialize ctx */
   setkey_func (ctx, key, sizeof(key));
@@ -357,10 +359,64 @@ _gcry_selftest_helper_ctr (const char *cipher, gcry_cipher_setkey_t setkey_func,
       return "selftest for CTR failed - see syslog for details";
     }
 
-  /* Test parallelized code paths */
+  /* Test bulk encryption with typical IV. */
+  memset(iv, 0x57, blocksize-4);
+  iv[blocksize-1] = 1;
+  iv[blocksize-2] = 0;
+  iv[blocksize-3] = 0;
+  iv[blocksize-4] = 0;
+  memset(iv2, 0x57, blocksize-4);
+  iv2[blocksize-1] = 1;
+  iv2[blocksize-2] = 0;
+  iv2[blocksize-3] = 0;
+  iv2[blocksize-4] = 0;
+
+  for (i = 0; i < blocksize * nblocks; i++)
+    plaintext2[i] = plaintext[i] = i;
+
+  /* Create CTR ciphertext manually.  */
+  for (i = 0; i < blocksize * nblocks; i+=blocksize)
+    {
+      encrypt_one (ctx, &ciphertext[i], iv);
+      for (j = 0; j < blocksize; j++)
+        ciphertext[i+j] ^= plaintext[i+j];
+      for (j = blocksize; j > 0; j--)
+        {
+          iv[j-1]++;
+          if (iv[j-1])
+            break;
+        }
+    }
+
+  bulk_ctr_enc (ctx, iv2, ciphertext2, plaintext2, nblocks);
+
+  if (memcmp (ciphertext2, ciphertext, blocksize * nblocks))
+    {
+      gcry_free (mem);
+#ifdef HAVE_SYSLOG
+      syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
+              "%s-CTR-%d test failed (plaintext mismatch, bulk)", cipher,
+              blocksize * 8);
+#endif
+      return "selftest for CTR failed - see syslog for details";
+    }
+  if (memcmp(iv2, iv, blocksize))
+    {
+      gcry_free (mem);
+#ifdef HAVE_SYSLOG
+      syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
+              "%s-CTR-%d test failed (IV mismatch, bulk)", cipher,
+              blocksize * 8);
+#endif
+      return "selftest for CTR failed - see syslog for details";
+    }
+
+  /* Test parallelized code paths (check counter overflow handling) */
   for (diff = 0; diff < nblocks; diff++) {
     memset(iv, 0xff, blocksize);
     iv[blocksize-1] -= diff;
+    iv[0] = iv[1] = 0;
+    iv[2] = 0x07;
 
     for (i = 0; i < blocksize * nblocks; i++)
       plaintext[i] = i;
@@ -382,6 +438,8 @@ _gcry_selftest_helper_ctr (const char *cipher, gcry_cipher_setkey_t setkey_func,
     /* Decrypt using bulk CTR and compare result.  */
     memset(iv2, 0xff, blocksize);
     iv2[blocksize-1] -= diff;
+    iv2[0] = iv2[1] = 0;
+    iv2[2] = 0x07;
 
     bulk_ctr_enc (ctx, iv2, plaintext2, ciphertext, nblocks);
 
@@ -389,7 +447,7 @@ _gcry_selftest_helper_ctr (const char *cipher, gcry_cipher_setkey_t setkey_func,
       {
         gcry_free (mem);
 #ifdef HAVE_SYSLOG
-        syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
+       fprintf(stderr, "Libgcrypt warning: "
                 "%s-CTR-%d test failed (plaintext mismatch, diff: %d)", cipher,
                blocksize * 8, diff);
 #endif
@@ -399,7 +457,7 @@ _gcry_selftest_helper_ctr (const char *cipher, gcry_cipher_setkey_t setkey_func,
       {
         gcry_free (mem);
 #ifdef HAVE_SYSLOG
-        syslog (LOG_USER|LOG_WARNING, "Libgcrypt warning: "
+       fprintf(stderr, "Libgcrypt warning: "
                 "%s-CTR-%d test failed (IV mismatch, diff: %d)", cipher,
                blocksize * 8, diff);
 #endif
index 532361d..3177574 100644 (file)
@@ -598,6 +598,9 @@ _gcry_serpent_avx2_ctr_enc:
         *      %rcx: iv (big endian, 128bit)
         */
 
+       movq 8(%rcx), %rax;
+       bswapq %rax;
+
        vzeroupper;
 
        vbroadcasti128 .Lbswap128_mask RIP, RTMP3;
@@ -614,25 +617,25 @@ _gcry_serpent_avx2_ctr_enc:
        vpshufb RTMP3, RTMP0, RA0; /* +1 ; +0 */
 
        /* check need for handling 64-bit overflow and carry */
-       cmpq $(0xffffffffffffffff - 16), (%rcx);
+       cmpq $(0xffffffffffffffff - 16), %rax;
        ja .Lhandle_ctr_carry;
 
        /* construct IVs */
-       vpsubq RTMP2, RTMP0, RA1; /* +3 ; +2 */
-       vpshufb RTMP3, RA1, RA1;
-       vpsubq RTMP2, RA1, RA2;   /* +5 ; +4 */
-       vpshufb RTMP3, RA2, RA2;
-       vpsubq RTMP2, RA2, RA3;   /* +7 ; +6 */
-       vpshufb RTMP3, RA3, RA3;
-       vpsubq RTMP2, RA3, RB0;   /* +9 ; +8 */
-       vpshufb RTMP3, RB0, RB0;
-       vpsubq RTMP2, RB0, RB1;   /* +11 ; +10 */
-       vpshufb RTMP3, RB1, RB1;
-       vpsubq RTMP2, RB1, RB2;   /* +13 ; +12 */
-       vpshufb RTMP3, RB2, RB2;
-       vpsubq RTMP2, RB2, RB3;   /* +15 ; +14 */
-       vpshufb RTMP3, RB3, RB3;
-       vpsubq RTMP2, RB3, RTMP0; /* +16 */
+       vpsubq RTMP2, RTMP0, RTMP0; /* +3 ; +2 */
+       vpshufb RTMP3, RTMP0, RA1;
+       vpsubq RTMP2, RTMP0, RTMP0; /* +5 ; +4 */
+       vpshufb RTMP3, RTMP0, RA2;
+       vpsubq RTMP2, RTMP0, RTMP0; /* +7 ; +6 */
+       vpshufb RTMP3, RTMP0, RA3;
+       vpsubq RTMP2, RTMP0, RTMP0; /* +9 ; +8 */
+       vpshufb RTMP3, RTMP0, RB0;
+       vpsubq RTMP2, RTMP0, RTMP0; /* +11 ; +10 */
+       vpshufb RTMP3, RTMP0, RB1;
+       vpsubq RTMP2, RTMP0, RTMP0; /* +13 ; +12 */
+       vpshufb RTMP3, RTMP0, RB2;
+       vpsubq RTMP2, RTMP0, RTMP0; /* +15 ; +14 */
+       vpshufb RTMP3, RTMP0, RB3;
+       vpsubq RTMP2, RTMP0, RTMP0; /* +16 */
        vpshufb RTMP3x, RTMP0x, RTMP0x;
 
        jmp .Lctr_carry_done;
index 4a24ddd..915cc95 100644 (file)
@@ -1158,7 +1158,7 @@ _gcry_serpent_cfb_dec(void *context, unsigned char *iv,
 static const char*
 selftest_ctr_128 (void)
 {
-  const int nblocks = 16+1;
+  const int nblocks = 16+8+1;
   const int blocksize = sizeof(serpent_block_t);
   const int context_size = sizeof(serpent_context_t);
 
@@ -1173,7 +1173,7 @@ selftest_ctr_128 (void)
 static const char*
 selftest_cbc_128 (void)
 {
-  const int nblocks = 16+2;
+  const int nblocks = 16+8+2;
   const int blocksize = sizeof(serpent_block_t);
   const int context_size = sizeof(serpent_context_t);
 
@@ -1188,7 +1188,7 @@ selftest_cbc_128 (void)
 static const char*
 selftest_cfb_128 (void)
 {
-  const int nblocks = 16+2;
+  const int nblocks = 16+8+2;
   const int blocksize = sizeof(serpent_block_t);
   const int context_size = sizeof(serpent_context_t);