CTR mode may now be used with arbitrary long data chunks.
authorWerner Koch <wk@gnupg.org>
Mon, 11 Apr 2011 19:36:48 +0000 (21:36 +0200)
committerWerner Koch <wk@gnupg.org>
Mon, 11 Apr 2011 19:36:48 +0000 (21:36 +0200)
NEWS
cipher/ChangeLog
cipher/cipher.c
tests/ChangeLog
tests/basic.c

diff --git a/NEWS b/NEWS
index add5152..b8d50e5 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -31,6 +31,8 @@ Noteworthy changes in version 1.5.x (unreleased)
 
  * New cipher algorithm mode for AES-WRAP.  [also in 1.4.6]
 
+ * CTR mode may now be used with data chunks of arbitrary length.
+
  * Fixed minor memory leak in DSA key generation.  [also in 1.4.5]
 
  * No more switching to FIPS mode if /proc/version is not
index 4cde857..ce955a1 100644 (file)
@@ -1,5 +1,10 @@
 2011-04-11  Werner Koch  <wk@g10code.com>
 
+       * cipher.c (_gcry_cipher_setctr): Clear unused lastiv info.
+       (gcry_cipher_ctl) <GCRYCTL_SET_CTR>: Implement by calling
+       _gcry_cipher_setctr.
+       (do_ctr_encrypt): Save last counter and reuse it.
+
        * cipher.c (do_ctr_encrypt): Allow arbitrary length inputs to
        match the 1.4 behaviour.
 
index e5bb2e0..90fdb17 100644 (file)
@@ -219,8 +219,9 @@ struct gcry_cipher_handle
     unsigned char ctr[MAX_BLOCKSIZE];
   } u_ctr;
 
+  /* Space to save an IV or CTR for chaining operations.  */
   unsigned char lastiv[MAX_BLOCKSIZE];
-  int unused;  /* Number of unused bytes in the IV. */
+  int unused;  /* Number of unused bytes in LASTIV. */
 
   /* What follows are two contexts of the cipher in use.  The first
      one needs to be aligned well enough for the cipher operation
@@ -1456,6 +1457,22 @@ do_ctr_encrypt (gcry_cipher_hd_t c,
   if (outbuflen < inbuflen)
     return GPG_ERR_BUFFER_TOO_SHORT;
 
+  /* First process a left over encrypted counter.  */
+  if (c->unused)
+    {
+      gcry_assert (c->unused < blocksize);
+      i = blocksize - c->unused;
+      for (n=0; c->unused && n < inbuflen; c->unused--, n++, i++)
+        {
+          /* XOR input with encrypted counter and store in output.  */
+          outbuf[n] = inbuf[n] ^ c->lastiv[i];
+        }
+      inbuf  += n;
+      outbuf += n;
+      inbuflen -= n;
+    }
+
+
   /* Use a bulk method if available.  */
   nblocks = inbuflen / blocksize;
   if (nblocks && c->bulk.ctr_enc)
@@ -1490,6 +1507,12 @@ do_ctr_encrypt (gcry_cipher_hd_t c,
           outbuf[n] = inbuf[n] ^ tmp[n % blocksize];
         }
 
+      /* Save the unused bytes of the counter.  */
+      n %= blocksize;
+      c->unused = (blocksize - n) % blocksize;
+      if (c->unused)
+        memcpy (c->lastiv+n, tmp+n, c->unused);
+
       wipememory (tmp, sizeof tmp);
     }
 
@@ -1884,9 +1907,15 @@ gpg_error_t
 _gcry_cipher_setctr (gcry_cipher_hd_t hd, const void *ctr, size_t ctrlen)
 {
   if (ctr && ctrlen == hd->cipher->blocksize)
-    memcpy (hd->u_ctr.ctr, ctr, hd->cipher->blocksize);
+    {
+      memcpy (hd->u_ctr.ctr, ctr, hd->cipher->blocksize);
+      hd->unused = 0;
+    }
   else if (!ctr || !ctrlen)
-    memset (hd->u_ctr.ctr, 0, hd->cipher->blocksize);
+    {
+      memset (hd->u_ctr.ctr, 0, hd->cipher->blocksize);
+      hd->unused = 0;
+    }
   else
     return gpg_error (GPG_ERR_INV_ARG);
   return 0;
@@ -1945,12 +1974,7 @@ gcry_cipher_ctl( gcry_cipher_hd_t h, int cmd, void *buffer, size_t buflen)
       break;
 
     case GCRYCTL_SET_CTR: /* Deprecated; use gcry_cipher_setctr.  */
-      if (buffer && buflen == h->cipher->blocksize)
-       memcpy (h->u_ctr.ctr, buffer, h->cipher->blocksize);
-      else if (buffer == NULL || buflen == 0)
-       memset (h->u_ctr.ctr, 0, h->cipher->blocksize);
-      else
-       rc = GPG_ERR_INV_ARG;
+      rc = gpg_err_code (_gcry_cipher_setctr (h, buffer, buflen));
       break;
 
     case 61:  /* Disable weak key detection (private).  */
index 3793149..ccaf3bd 100644 (file)
@@ -2,7 +2,7 @@
 
        * basic.c (mismatch): New.
        (check_ctr_cipher): Remove length error code checks.  Add
-       truncation checks.
+       truncation and streaming checks.
 
 2011-04-04  Werner Koch  <wk@g10code.com>
 
index a20e731..2216476 100644 (file)
@@ -365,7 +365,7 @@ check_ctr_cipher (void)
       unsigned char plaintext[MAX_DATA_LEN];
       int inlen;
       char out[MAX_DATA_LEN];
-    } data[5];
+    } data[8];
   } tv[] =
     {
       /* http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf */
@@ -470,6 +470,54 @@ check_ctr_cipher (void)
          {"", 0, "" }
        }
       },
+      /* Tests to see whether it works correctly as a stream cipher.  */
+      {        GCRY_CIPHER_AES,
+       "\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
+       "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+       {{"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a",
+          16,
+          "\x87\x4d\x61\x91\xb6\x20\xe3\x26\x1b\xef\x68\x64\x99\x0d\xb6\xce" },
+         {"\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e",
+          15,
+          "\x98\x06\xf6\x6b\x79\x70\xfd\xff\x86\x17\x18\x7b\xb9\xff\xfd" },
+         {"\x51\x30\xc8\x1c\x46\xa3\x5c\xe4\x11\xe5\xfb\xc1\x19\x1a\x0a\x52\xef",
+          17,
+          "\xff\x5a\xe4\xdf\x3e\xdb\xd5\xd3\x5e\x5b\x4f\x09\x02\x0d\xb0\x3e\xab" },
+         {"\xf6\x9f\x24\x45\xdf\x4f\x9b\x17\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+          16,
+          "\x1e\x03\x1d\xda\x2f\xbe\x03\xd1\x79\x21\x70\xa0\xf3\x00\x9c\xee" },
+
+          { "", 0, "" }
+       }
+      },
+      {        GCRY_CIPHER_AES,
+       "\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
+       "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+       {{"\x6b",
+          1,
+          "\x87" },
+        {"\xc1\xbe",
+          2,
+          "\x4d\x61" },
+        {"\xe2\x2e\x40",
+          3,
+          "\x91\xb6\x20" },
+        {"\x9f",
+          1,
+          "\xe3" },
+        {"\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a",
+          9,
+          "\x26\x1b\xef\x68\x64\x99\x0d\xb6\xce" },
+         {"\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e",
+          15,
+          "\x98\x06\xf6\x6b\x79\x70\xfd\xff\x86\x17\x18\x7b\xb9\xff\xfd" },
+         {"\x51\x30\xc8\x1c\x46\xa3\x5c\xe4\x11",
+          9,
+          "\xff\x5a\xe4\xdf\x3e\xdb\xd5\xd3\x5e" },
+
+          { "", 0, "" }
+       }
+      },
 #if USE_CAST5
       /* A selfmade test vector using an 64 bit block cipher.  */
       {        GCRY_CIPHER_CAST5,