Applied OFB mode patch by Brad Harris
authorWerner Koch <wk@gnupg.org>
Tue, 7 Mar 2006 19:26:21 +0000 (19:26 +0000)
committerWerner Koch <wk@gnupg.org>
Tue, 7 Mar 2006 19:26:21 +0000 (19:26 +0000)
AUTHORS
TODO
cipher/ChangeLog
cipher/cipher.c
doc/ChangeLog
doc/gcrypt.texi
tests/ChangeLog
tests/basic.c
tests/benchmark.c

diff --git a/AUTHORS b/AUTHORS
index 45499ff..b3b398d 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -23,20 +23,17 @@ Wrote cipher/twofish.c.
 GNUPG  Natural Resources Canada    1998-08-11
 Disclaims changes by Matthew Skala.
 
-
 GNUPG  Michael Roth    Germany     1998-09-17
 Assigns changes.
 mroth@nessie.de
 Wrote cipher/des.c.
 Changes and bug fixes all over the place.
 
-
 GNUPG  Niklas Hernaeus         1998-09-18
 Disclaims changes.
 nh@df.lth.se
 Weak key patches.
 
-
 GNUPG  RĂ©mi Guyomarch          1999-05-25
 Assigns past and future changes. (g10/compress.c, g10/encr-data.c,
 g10/free-packet.c, g10/mdfilter.c, g10/plaintext.c, util/iobuf.c)
@@ -70,6 +67,13 @@ mpi/hppa1.1/mpih-mul1.S, mpi/Makefile.am, tests/prime.c,
 tests/register.c, tests/ac.c, tests/basic.c, tests/tsexp.c,
 tests/keygen.c, tests/pubkey.c, configure.ac, acinclude.m4)
 
+LIBGCRYPT       Brad Hards       2006-02-09
+Assigns Past and Future Changes
+bradh@frogmouth.net
+(Added OFB mode. Changed cipher/cipher.c, test/basic.c doc/gcrypt.tex)
+
+
+
 
 More credits
 ============
@@ -85,7 +89,8 @@ files from Cryptlib.  Copyright Peter Gutmann, Paul Kendall, and Chris
 Wedgwood 1996-1999.
 
 
- Copyright 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+ Copyright 1998, 1999, 2000, 2001, 2002, 2003,
+           2006 Free Software Foundation, Inc.
 
  This file is free software; as a special exception the author gives
  unlimited permission to copy and/or distribute it, with or without
diff --git a/TODO b/TODO
index 43a432b..6d6355f 100644 (file)
--- a/TODO
+++ b/TODO
@@ -36,3 +36,6 @@ What's left to do                                 -*- outline -*-
 * update/improve documentation
   - it's outdated for e.g. gcry_pk_algo_info.
   - document algorithm capabilities
+
+* Use builtin bit functions of gcc 3.4
+
index c70ebca..792bd82 100644 (file)
@@ -1,3 +1,8 @@
+2006-01-18  Brad Hards  <bradh@frogmouth.net>  (wk 2006-03-07)
+
+       * cipher.c (cipher_encrypt, cipher_decrypt, do_ofb_encrypt)
+       (do_ofb_decrypt, gcry_cipher_open): Implement Output Feedback Mode.
+
 2005-11-02  Moritz Schulte  <moritz@g10code.com>
 
        * pubkey.c (gcry_pk_algo_name): Return "?" instead of NULL for
index 087a347..03b1752 100644 (file)
@@ -590,6 +590,7 @@ gcry_cipher_open (gcry_cipher_hd_t *handle,
       case GCRY_CIPHER_MODE_ECB:
       case GCRY_CIPHER_MODE_CBC:
       case GCRY_CIPHER_MODE_CFB:
+      case GCRY_CIPHER_MODE_OFB:
       case GCRY_CIPHER_MODE_CTR:
        if ((cipher->encrypt == dummy_encrypt_block)
            || (cipher->decrypt == dummy_decrypt_block))
@@ -983,6 +984,100 @@ do_cfb_decrypt( gcry_cipher_hd_t c,
 
 
 static void
+do_ofb_encrypt( gcry_cipher_hd_t c,
+                byte *outbuf, const byte *inbuf, unsigned nbytes )
+{
+  byte *ivp;
+  size_t blocksize = c->cipher->blocksize;
+
+  if ( nbytes <= c->unused )
+    {
+      /* Short enough to be encoded by the remaining XOR mask. */
+      /* XOR the input with the IV */
+      for (ivp=c->iv+c->cipher->blocksize - c->unused;
+           nbytes;
+           nbytes--, c->unused-- )
+        *outbuf++ = (*ivp++ ^ *inbuf++);
+      return;
+    }
+
+  if( c->unused )
+    {
+      nbytes -= c->unused;
+      for(ivp=c->iv+blocksize - c->unused; c->unused; c->unused-- )
+        *outbuf++ = (*ivp++ ^ *inbuf++);
+    }
+
+  /* Now we can process complete blocks. */
+  while ( nbytes >= blocksize )
+    {
+      int i;
+      /* Encrypt the IV (and save the current one). */
+      memcpy( c->lastiv, c->iv, blocksize );
+      c->cipher->encrypt ( &c->context.c, c->iv, c->iv );
+      
+      for (ivp=c->iv,i=0; i < blocksize; i++ )
+        *outbuf++ = (*ivp++ ^ *inbuf++);
+      nbytes -= blocksize;
+    }
+  if ( nbytes )
+    { /* process the remaining bytes */
+      memcpy( c->lastiv, c->iv, blocksize );
+      c->cipher->encrypt ( &c->context.c, c->iv, c->iv );
+      c->unused = blocksize;
+      c->unused -= nbytes;
+      for(ivp=c->iv; nbytes; nbytes-- )
+        *outbuf++ = (*ivp++ ^ *inbuf++);
+    }
+}
+
+static void
+do_ofb_decrypt( gcry_cipher_hd_t c,
+                byte *outbuf, const byte *inbuf, unsigned int nbytes )
+{
+  byte *ivp;
+  size_t blocksize = c->cipher->blocksize;
+  
+  if( nbytes <= c->unused )
+    {
+      /* Short enough to be encoded by the remaining XOR mask. */
+      for (ivp=c->iv+blocksize - c->unused; nbytes; nbytes--,c->unused--)
+        *outbuf++ = *ivp++ ^ *inbuf++;
+      return;
+    }
+
+  if ( c->unused )
+    {
+      nbytes -= c->unused;
+      for (ivp=c->iv+blocksize - c->unused; c->unused; c->unused-- )
+        *outbuf++ = *ivp++ ^ *inbuf++;
+    }
+
+  /* Now we can process complete blocks. */
+  while ( nbytes >= blocksize )
+    {
+      int i;
+      /* Encrypt the IV (and save the current one). */
+      memcpy( c->lastiv, c->iv, blocksize );
+      c->cipher->encrypt ( &c->context.c, c->iv, c->iv );
+      for (ivp=c->iv,i=0; i < blocksize; i++ )
+        *outbuf++ = *ivp++ ^ *inbuf++;
+      nbytes -= blocksize;
+    }
+  if ( nbytes ) 
+    { /* Process the remaining bytes. */
+      /* Encrypt the IV (and save the current one). */
+      memcpy( c->lastiv, c->iv, blocksize );
+      c->cipher->encrypt ( &c->context.c, c->iv, c->iv );
+      c->unused = blocksize;
+      c->unused -= nbytes;
+      for (ivp=c->iv; nbytes; nbytes-- )
+        *outbuf++ = *ivp++ ^ *inbuf++;
+    }
+}
+
+
+static void
 do_ctr_encrypt( gcry_cipher_hd_t c, byte *outbuf, const byte *inbuf,
                 unsigned int nbytes )
 {
@@ -1046,6 +1141,9 @@ cipher_encrypt (gcry_cipher_hd_t c, byte *outbuf,
       case GCRY_CIPHER_MODE_CFB:
        do_cfb_encrypt(c, outbuf, inbuf, nbytes );
        break;
+      case GCRY_CIPHER_MODE_OFB:
+       do_ofb_encrypt(c, outbuf, inbuf, nbytes );
+       break;
       case GCRY_CIPHER_MODE_CTR:
        do_ctr_encrypt(c, outbuf, inbuf, nbytes );
        break;
@@ -1132,6 +1230,9 @@ cipher_decrypt (gcry_cipher_hd_t c, byte *outbuf, const byte *inbuf,
       case GCRY_CIPHER_MODE_CFB:
        do_cfb_decrypt(c, outbuf, inbuf, nbytes );
        break;
+      case GCRY_CIPHER_MODE_OFB:
+       do_ofb_decrypt(c, outbuf, inbuf, nbytes );
+       break;
       case GCRY_CIPHER_MODE_CTR:
        do_ctr_decrypt(c, outbuf, inbuf, nbytes );
        break;
index 797396d..e0b5411 100644 (file)
@@ -1,3 +1,8 @@
+2006-01-18  Brad Hards  <bradh@frogmouth.net> (wk 2006-03-07)
+
+       * gcrypt.texi (Available cipher modes): Typo fix, add a little
+       more detail on cipher modes vs cipher algorithms.
+
 2006-01-08  Moritz Schulte  <moritz@g10code.com>
 
        * gcrypt.texi: Added documentation for more gcry_control commands.
index 907f7bb..fa32a3a 100644 (file)
@@ -12,7 +12,7 @@ This manual is for Libgcrypt
 (version @value{VERSION}, @value{UPDATED}),
 which is GNU's library of cryptographic building blocks.
 
-Copyright @copyright{} 2000, 2002, 2003, 2004 Free Software Foundation, Inc.
+Copyright @copyright{} 2000, 2002, 2003, 2004, 2006 Free Software Foundation, Inc.
 
 @quotation
 Permission is granted to copy, distribute and/or modify this document
@@ -1318,7 +1318,7 @@ Cipher Block Chaining mode.
 Stream mode, only to be used with stream cipher algorithms.
 
 @item GCRY_CIPHER_MODE_OFB
-Outer Feedback mode.
+Output Feedback mode.
 
 @item  GCRY_CIPHER_MODE_CTR
 Counter mode.
@@ -1347,8 +1347,12 @@ an algorithm into the according numeric ID.
 
 The cipher mode to use must be specified via @var{mode}.  See
 @xref{Available cipher modes}, for a list of supported cipher modes
-and the according constants.  Note, that some modes do not work
-together with all algorithms.
+and the according constants.  Note that some modes are incompatible
+with some algorithms - in particular, stream mode
+(GCRY_CIPHER_MODE_STREAM) only works with stream ciphers. Any block
+cipher mode (GCRY_CIPHER_MODE_ECB, GCRY_CIPHER_MODE_CBC,
+GCRY_CIPHER_MODE_CFB, GCRY_CIPHER_MODE_OFB or GCRY_CIPHER_MODE_CTR)
+will work with any block cipher algorithm.
 
 The third argument @var{flags} can either be passed as @code{0} or as
 the bit-wise OR of the following constants.
index bd86b5f..4d78663 100644 (file)
@@ -1,3 +1,12 @@
+2006-03-07  Werner Koch  <wk@g10code.com>
+
+       * benchmark.c (cipher_bench): Add OFB mode.
+
+2006-01-18  Brad Hards  <bradh@frogmouth.net> (wk 2006-03-07)
+
+       * basic.c: Added test cases for OFB and CFB modes. Fixed some
+       compiler warnings for signedness. 
+
 2005-11-12  Moritz Schulte  <moritz@g10code.com>
 
        * ac-data.c: Added way more test cases.
index f5444dc..29e0054 100644 (file)
@@ -89,7 +89,7 @@ check_cbc_mac_cipher (void)
   {
     int algo;
     char key[MAX_DATA_LEN];
-    char plaintext[MAX_DATA_LEN];
+    unsigned char plaintext[MAX_DATA_LEN];
     size_t plaintextlen;
     char mac[MAX_DATA_LEN];
   }
@@ -109,7 +109,7 @@ check_cbc_mac_cipher (void)
        0, "\xfa\x4b\xdf\x9d\xfa\xab\x01\x70" }
     };
   gcry_cipher_hd_t hd;
-  char out[MAX_DATA_LEN];
+  unsigned char out[MAX_DATA_LEN];
   int i, blklen, keylen;
   gcry_error_t err = 0;
 
@@ -165,7 +165,7 @@ check_cbc_mac_cipher (void)
                                 tv[i].plaintext,
                                 tv[i].plaintextlen ?
                                 tv[i].plaintextlen :
-                                strlen (tv[i].plaintext));
+                                strlen ((char*)tv[i].plaintext));
       if (err)
        {
          fail ("cbc-mac algo %d, gcry_cipher_encrypt failed: %s\n",
@@ -194,11 +194,11 @@ static void
 check_aes128_cbc_cts_cipher (void)
 {
   char key[128 / 8] = "chicken teriyaki";
-  char plaintext[] =
+  unsigned char plaintext[] =
     "I would like the General Gau's Chicken, please, and wonton soup.";
   struct tv
   {
-    char out[MAX_DATA_LEN];
+    unsigned char out[MAX_DATA_LEN];
     int inlen;
   } tv[] =
     {
@@ -226,7 +226,7 @@ check_aes128_cbc_cts_cipher (void)
        64 },
     };
   gcry_cipher_hd_t hd;
-  char out[MAX_DATA_LEN];
+  unsigned char out[MAX_DATA_LEN];
   int i;
   gcry_error_t err = 0;
 
@@ -306,7 +306,7 @@ check_ctr_cipher (void)
     char ctr[MAX_DATA_LEN];
     struct data
     {
-      char plaintext[MAX_DATA_LEN];
+      unsigned char plaintext[MAX_DATA_LEN];
       int inlen;
       char out[MAX_DATA_LEN];
     }
@@ -369,7 +369,7 @@ check_ctr_cipher (void)
       }
     };
   gcry_cipher_hd_t hde, hdd;
-  char out[MAX_DATA_LEN];
+  unsigned char out[MAX_DATA_LEN];
   int i, j, keylen, blklen;
   gcry_error_t err = 0;
 
@@ -427,7 +427,7 @@ check_ctr_cipher (void)
          err = gcry_cipher_encrypt (hde, out, MAX_DATA_LEN,
                                     tv[i].data[j].plaintext,
                                     tv[i].data[j].inlen == -1 ?
-                                    strlen (tv[i].data[j].plaintext) :
+                                    strlen ((char*)tv[i].data[j].plaintext) :
                                     tv[i].data[j].inlen);
          if (err)
            {
@@ -461,10 +461,399 @@ check_ctr_cipher (void)
 }
 
 static void
+check_cfb_cipher (void)
+{
+  struct tv
+  {
+    int algo;
+    char key[MAX_DATA_LEN];
+    char iv[MAX_DATA_LEN];
+    struct data
+    {
+      unsigned char plaintext[MAX_DATA_LEN];
+      int inlen;
+      char out[MAX_DATA_LEN];
+    }
+    data[MAX_DATA_LEN];
+  } tv[] =
+    {
+      /* http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf */
+      { GCRY_CIPHER_AES,
+        "\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
+        "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+        { { "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a",
+            16,
+            "\x3b\x3f\xd9\x2e\xb7\x2d\xad\x20\x33\x34\x49\xf8\xe8\x3c\xfb\x4a" },
+          { "\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51",
+            16,
+            "\xc8\xa6\x45\x37\xa0\xb3\xa9\x3f\xcd\xe3\xcd\xad\x9f\x1c\xe5\x8b"},
+          { "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11\xe5\xfb\xc1\x19\x1a\x0a\x52\xef",
+            16,
+            "\x26\x75\x1f\x67\xa3\xcb\xb1\x40\xb1\x80\x8c\xf1\x87\xa4\xf4\xdf" },
+          { "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+            16,
+            "\xc0\x4b\x05\x35\x7c\x5d\x1c\x0e\xea\xc4\xc6\x6f\x9f\xf7\xf2\xe6" },
+        }
+      },
+      { GCRY_CIPHER_AES192,
+        "\x8e\x73\xb0\xf7\xda\x0e\x64\x52\xc8\x10\xf3\x2b"
+        "\x80\x90\x79\xe5\x62\xf8\xea\xd2\x52\x2c\x6b\x7b",
+        "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+        { { "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a",
+            16,
+            "\xcd\xc8\x0d\x6f\xdd\xf1\x8c\xab\x34\xc2\x59\x09\xc9\x9a\x41\x74" },
+          { "\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51",
+            16,
+            "\x67\xce\x7f\x7f\x81\x17\x36\x21\x96\x1a\x2b\x70\x17\x1d\x3d\x7a" },
+          { "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11\xe5\xfb\xc1\x19\x1a\x0a\x52\xef",
+            16,
+            "\x2e\x1e\x8a\x1d\xd5\x9b\x88\xb1\xc8\xe6\x0f\xed\x1e\xfa\xc4\xc9" },
+          { "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+            16,
+            "\xc0\x5f\x9f\x9c\xa9\x83\x4f\xa0\x42\xae\x8f\xba\x58\x4b\x09\xff" },
+        }
+      },
+      { GCRY_CIPHER_AES256,
+        "\x60\x3d\xeb\x10\x15\xca\x71\xbe\x2b\x73\xae\xf0\x85\x7d\x77\x81"
+        "\x1f\x35\x2c\x07\x3b\x61\x08\xd7\x2d\x98\x10\xa3\x09\x14\xdf\xf4",
+        "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+        { { "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a",
+            16,
+            "\xdc\x7e\x84\xbf\xda\x79\x16\x4b\x7e\xcd\x84\x86\x98\x5d\x38\x60" },
+          { "\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51",
+            16,
+            "\x39\xff\xed\x14\x3b\x28\xb1\xc8\x32\x11\x3c\x63\x31\xe5\x40\x7b" },
+          { "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11\xe5\xfb\xc1\x19\x1a\x0a\x52\xef",
+            16,
+            "\xdf\x10\x13\x24\x15\xe5\x4b\x92\xa1\x3e\xd0\xa8\x26\x7a\xe2\xf9" },
+          { "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+            16,
+            "\x75\xa3\x85\x74\x1a\xb9\xce\xf8\x20\x31\x62\x3d\x55\xb1\xe4\x71" }
+        }
+      }
+    };
+  gcry_cipher_hd_t hde, hdd;
+  unsigned char out[MAX_DATA_LEN];
+  int i, j, keylen, blklen;
+  gcry_error_t err = 0;
+
+  for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++)
+    {
+      err = gcry_cipher_open (&hde, tv[i].algo, GCRY_CIPHER_MODE_CFB, 0);
+      if (!err)
+        err = gcry_cipher_open (&hdd, tv[i].algo, GCRY_CIPHER_MODE_CFB, 0);
+      if (err)
+        {
+          fail ("aes-cfb, grcy_open_cipher failed: %s\n", gpg_strerror (err));
+          return;
+        }
+
+      keylen = gcry_cipher_get_algo_keylen(tv[i].algo);
+      if (!keylen)
+        {
+          fail ("aes-cfb, gcry_cipher_get_algo_keylen failed\n");
+          return;
+        }
+
+      err = gcry_cipher_setkey (hde, tv[i].key, keylen);
+      if (!err)
+        err = gcry_cipher_setkey (hdd, tv[i].key, keylen);
+      if (err)
+        {
+          fail ("aes-cfb, gcry_cipher_setkey failed: %s\n",
+                gpg_strerror (err));
+          gcry_cipher_close (hde);
+          gcry_cipher_close (hdd);
+          return;
+        }
+
+      blklen = gcry_cipher_get_algo_blklen(tv[i].algo);
+      if (!blklen)
+        {
+          fail ("aes-cfb, gcry_cipher_get_algo_blklen failed\n");
+          return;
+        }
+
+      err = gcry_cipher_setiv (hde, tv[i].iv, blklen);
+      if (!err)
+        err = gcry_cipher_setiv (hdd, tv[i].iv, blklen);
+      if (err)
+        {
+          fail ("aes-cfb, gcry_cipher_setiv failed: %s\n",
+                gpg_strerror (err));
+          gcry_cipher_close (hde);
+          gcry_cipher_close (hdd);
+          return;
+        }
+
+      for (j = 0; tv[i].data[j].inlen; j++)
+        {
+          err = gcry_cipher_encrypt (hde, out, MAX_DATA_LEN,
+                                     tv[i].data[j].plaintext,
+                                     tv[i].data[j].inlen);
+          if (err)
+            {
+              fail ("aes-cfb, gcry_cipher_encrypt (%d, %d) failed: %s\n",
+                    i, j, gpg_strerror (err));
+              gcry_cipher_close (hde);
+              gcry_cipher_close (hdd);
+              return;
+            }
+
+          if (memcmp (tv[i].data[j].out, out, tv[i].data[j].inlen)) {
+            fail ("aes-cfb, encrypt mismatch entry %d:%d\n", i, j);
+         }
+          err = gcry_cipher_decrypt (hdd, out, tv[i].data[j].inlen, NULL, 0);
+          if (err)
+            {
+              fail ("aes-cfb, gcry_cipher_decrypt (%d, %d) failed: %s\n",
+                    i, j, gpg_strerror (err));
+              gcry_cipher_close (hde);
+              gcry_cipher_close (hdd);
+              return;
+            }
+
+          if (memcmp (tv[i].data[j].plaintext, out, tv[i].data[j].inlen))
+            fail ("aes-cfb, decrypt mismatch entry %d:%d\n", i, j);
+        }
+
+      gcry_cipher_close (hde);
+      gcry_cipher_close (hdd);
+    }
+}
+
+static void
+check_ofb_cipher (void)
+{
+  struct tv
+  {
+    int algo;
+    char key[MAX_DATA_LEN];
+    char iv[MAX_DATA_LEN];
+    struct data
+    {
+      unsigned char plaintext[MAX_DATA_LEN];
+      int inlen;
+      char out[MAX_DATA_LEN];
+    }
+    data[MAX_DATA_LEN];
+  } tv[] =
+    {
+      /* http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf */
+      { GCRY_CIPHER_AES,
+        "\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c",
+        "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+        { { "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a",
+            16,
+            "\x3b\x3f\xd9\x2e\xb7\x2d\xad\x20\x33\x34\x49\xf8\xe8\x3c\xfb\x4a" },
+          { "\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51",
+            16,
+            "\x77\x89\x50\x8d\x16\x91\x8f\x03\xf5\x3c\x52\xda\xc5\x4e\xd8\x25"},
+          { "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11\xe5\xfb\xc1\x19\x1a\x0a\x52\xef",
+            16,
+            "\x97\x40\x05\x1e\x9c\x5f\xec\xf6\x43\x44\xf7\xa8\x22\x60\xed\xcc" },
+          { "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+            16,
+            "\x30\x4c\x65\x28\xf6\x59\xc7\x78\x66\xa5\x10\xd9\xc1\xd6\xae\x5e" },
+        }
+      },
+      { GCRY_CIPHER_AES192,
+        "\x8e\x73\xb0\xf7\xda\x0e\x64\x52\xc8\x10\xf3\x2b"
+        "\x80\x90\x79\xe5\x62\xf8\xea\xd2\x52\x2c\x6b\x7b",
+        "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+        { { "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a",
+            16,
+            "\xcd\xc8\x0d\x6f\xdd\xf1\x8c\xab\x34\xc2\x59\x09\xc9\x9a\x41\x74" },
+          { "\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51",
+            16,
+            "\xfc\xc2\x8b\x8d\x4c\x63\x83\x7c\x09\xe8\x17\x00\xc1\x10\x04\x01" },
+          { "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11\xe5\xfb\xc1\x19\x1a\x0a\x52\xef",
+            16,
+            "\x8d\x9a\x9a\xea\xc0\xf6\x59\x6f\x55\x9c\x6d\x4d\xaf\x59\xa5\xf2" },
+          { "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+            16,
+            "\x6d\x9f\x20\x08\x57\xca\x6c\x3e\x9c\xac\x52\x4b\xd9\xac\xc9\x2a" },
+        }
+      },
+      { GCRY_CIPHER_AES256,
+        "\x60\x3d\xeb\x10\x15\xca\x71\xbe\x2b\x73\xae\xf0\x85\x7d\x77\x81"
+        "\x1f\x35\x2c\x07\x3b\x61\x08\xd7\x2d\x98\x10\xa3\x09\x14\xdf\xf4",
+        "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+        { { "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a",
+            16,
+            "\xdc\x7e\x84\xbf\xda\x79\x16\x4b\x7e\xcd\x84\x86\x98\x5d\x38\x60" },
+          { "\xae\x2d\x8a\x57\x1e\x03\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51",
+            16,
+            "\x4f\xeb\xdc\x67\x40\xd2\x0b\x3a\xc8\x8f\x6a\xd8\x2a\x4f\xb0\x8d" },
+          { "\x30\xc8\x1c\x46\xa3\x5c\xe4\x11\xe5\xfb\xc1\x19\x1a\x0a\x52\xef",
+            16,
+            "\x71\xab\x47\xa0\x86\xe8\x6e\xed\xf3\x9d\x1c\x5b\xba\x97\xc4\x08" },
+          { "\xf6\x9f\x24\x45\xdf\x4f\x9b\x17\xad\x2b\x41\x7b\xe6\x6c\x37\x10",
+            16,
+            "\x01\x26\x14\x1d\x67\xf3\x7b\xe8\x53\x8f\x5a\x8b\xe7\x40\xe4\x84" }
+        }
+      }
+    };
+  gcry_cipher_hd_t hde, hdd;
+  unsigned char out[MAX_DATA_LEN];
+  int i, j, keylen, blklen;
+  gcry_error_t err = 0;
+
+  for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++)
+    {
+      err = gcry_cipher_open (&hde, tv[i].algo, GCRY_CIPHER_MODE_OFB, 0);
+      if (!err)
+        err = gcry_cipher_open (&hdd, tv[i].algo, GCRY_CIPHER_MODE_OFB, 0);
+      if (err)
+        {
+          fail ("aes-ofb, grcy_open_cipher failed: %s\n", gpg_strerror (err));
+          return;
+        }
+
+      keylen = gcry_cipher_get_algo_keylen(tv[i].algo);
+      if (!keylen)
+        {
+          fail ("aes-ofb, gcry_cipher_get_algo_keylen failed\n");
+          return;
+        }
+
+      err = gcry_cipher_setkey (hde, tv[i].key, keylen);
+      if (!err)
+        err = gcry_cipher_setkey (hdd, tv[i].key, keylen);
+      if (err)
+        {
+          fail ("aes-ofb, gcry_cipher_setkey failed: %s\n",
+                gpg_strerror (err));
+          gcry_cipher_close (hde);
+          gcry_cipher_close (hdd);
+          return;
+        }
+
+      blklen = gcry_cipher_get_algo_blklen(tv[i].algo);
+      if (!blklen)
+        {
+          fail ("aes-ofb, gcry_cipher_get_algo_blklen failed\n");
+          return;
+        }
+
+      err = gcry_cipher_setiv (hde, tv[i].iv, blklen);
+      if (!err)
+        err = gcry_cipher_setiv (hdd, tv[i].iv, blklen);
+      if (err)
+        {
+          fail ("aes-ofb, gcry_cipher_setiv failed: %s\n",
+                gpg_strerror (err));
+          gcry_cipher_close (hde);
+          gcry_cipher_close (hdd);
+          return;
+        }
+
+      for (j = 0; tv[i].data[j].inlen; j++)
+        {
+          err = gcry_cipher_encrypt (hde, out, MAX_DATA_LEN,
+                                     tv[i].data[j].plaintext,
+                                     tv[i].data[j].inlen);
+          if (err)
+            {
+              fail ("aes-ofb, gcry_cipher_encrypt (%d, %d) failed: %s\n",
+                    i, j, gpg_strerror (err));
+              gcry_cipher_close (hde);
+              gcry_cipher_close (hdd);
+              return;
+            }
+
+          if (memcmp (tv[i].data[j].out, out, tv[i].data[j].inlen))
+            fail ("aes-ofb, encrypt mismatch entry %d:%d\n", i, j);
+
+          err = gcry_cipher_decrypt (hdd, out, tv[i].data[j].inlen, NULL, 0);
+          if (err)
+            {
+              fail ("aes-ofb, gcry_cipher_decrypt (%d, %d) failed: %s\n",
+                    i, j, gpg_strerror (err));
+              gcry_cipher_close (hde);
+              gcry_cipher_close (hdd);
+              return;
+            }
+
+          if (memcmp (tv[i].data[j].plaintext, out, tv[i].data[j].inlen))
+            fail ("aes-ofb, decrypt mismatch entry %d:%d\n", i, j);
+        }
+
+      err = gcry_cipher_reset(hde);
+      if (!err)
+       err = gcry_cipher_reset(hdd);
+      if (err)
+       {
+         fail ("aes-ofb, gcry_cipher_reset (%d, %d) failed: %s\n",
+               i, j, gpg_strerror (err));
+         gcry_cipher_close (hde);
+         gcry_cipher_close (hdd);
+         return;
+       }
+
+      /* gcry_cipher_reset clears the IV */
+      err = gcry_cipher_setiv (hde, tv[i].iv, blklen);
+      if (!err)
+        err = gcry_cipher_setiv (hdd, tv[i].iv, blklen);
+      if (err)
+        {
+          fail ("aes-ofb, gcry_cipher_setiv failed: %s\n",
+                gpg_strerror (err));
+          gcry_cipher_close (hde);
+          gcry_cipher_close (hdd);
+          return;
+        }
+
+      /* this time we encrypt and decrypt one byte at a time */
+      for (j = 0; tv[i].data[j].inlen; j++)
+        {
+         int byteNum;
+         for (byteNum = 0; byteNum < tv[i].data[j].inlen; ++byteNum) 
+           {
+             err = gcry_cipher_encrypt (hde, out+byteNum, 1,
+                                        (tv[i].data[j].plaintext) + byteNum,
+                                        1);
+             if (err)
+               {
+                 fail ("aes-ofb, gcry_cipher_encrypt (%d, %d) failed: %s\n",
+                       i, j, gpg_strerror (err));
+                 gcry_cipher_close (hde);
+                 gcry_cipher_close (hdd);
+                 return;
+               }
+           }
+
+          if (memcmp (tv[i].data[j].out, out, tv[i].data[j].inlen))
+            fail ("aes-ofb, encrypt mismatch entry %d:%d\n", i, j);
+
+         for (byteNum = 0; byteNum < tv[i].data[j].inlen; ++byteNum) 
+           {
+             err = gcry_cipher_decrypt (hdd, out+byteNum, 1, NULL, 0);
+             if (err)
+               {
+                 fail ("aes-ofb, gcry_cipher_decrypt (%d, %d) failed: %s\n",
+                       i, j, gpg_strerror (err));
+                 gcry_cipher_close (hde);
+                 gcry_cipher_close (hdd);
+                 return;
+               }
+           }
+
+          if (memcmp (tv[i].data[j].plaintext, out, tv[i].data[j].inlen))
+            fail ("aes-ofb, decrypt mismatch entry %d:%d\n", i, j);
+        }
+
+      gcry_cipher_close (hde);
+      gcry_cipher_close (hdd);
+    }
+}
+
+static void
 check_one_cipher (int algo, int mode, int flags)
 {
   gcry_cipher_hd_t hd;
-  char key[32], plain[16], in[16], out[16];
+  char key[32];
+  unsigned char plain[16], in[16], out[16];
   int keylen;
   gcry_error_t err = 0;
 
@@ -562,6 +951,7 @@ check_ciphers (void)
 
       check_one_cipher (algos[i], GCRY_CIPHER_MODE_ECB, 0);
       check_one_cipher (algos[i], GCRY_CIPHER_MODE_CFB, 0);
+      check_one_cipher (algos[i], GCRY_CIPHER_MODE_OFB, 0);
       check_one_cipher (algos[i], GCRY_CIPHER_MODE_CBC, 0);
       check_one_cipher (algos[i], GCRY_CIPHER_MODE_CBC, GCRY_CIPHER_CBC_CTS);
       check_one_cipher (algos[i], GCRY_CIPHER_MODE_CTR, 0);
@@ -586,7 +976,7 @@ static void
 check_one_md (int algo, char *data, int len, char *expect)
 {
   gcry_md_hd_t hd, hd2;
-  char *p;
+  unsigned char *p;
   int mdlen;
   int i;
   gcry_error_t err = 0;
@@ -1117,6 +1507,8 @@ main (int argc, char **argv)
   check_aes128_cbc_cts_cipher ();
   check_cbc_mac_cipher ();
   check_ctr_cipher ();
+  check_cfb_cipher ();
+  check_ofb_cipher ();
   check_digests ();
   check_pubkey ();
 
index 04cfedc..1d82c5d 100644 (file)
@@ -358,6 +358,7 @@ cipher_bench ( const char *algoname )
     { GCRY_CIPHER_MODE_ECB, "ECB", 1 },
     { GCRY_CIPHER_MODE_CBC, "CBC", 1 },
     { GCRY_CIPHER_MODE_CFB, "CFB", 0 },
+    { GCRY_CIPHER_MODE_OFB, "OFB", 0 },
     { GCRY_CIPHER_MODE_CTR, "CTR", 0 },
     { GCRY_CIPHER_MODE_STREAM, "STREAM", 0 },
     {0}