Limit and document Blowfish key lengths to 8-576 bits
authorJussi Kivilinna <jussi.kivilinna@iki.fi>
Thu, 18 Apr 2019 15:53:35 +0000 (18:53 +0300)
committerJussi Kivilinna <jussi.kivilinna@iki.fi>
Thu, 18 Apr 2019 15:53:35 +0000 (18:53 +0300)
* cipher/blowfish.c (BLOWFISH_KEY_MIN_BITS)
(BLOWFISH_KEY_MAX_BITS): New.
(do_bf_setkey): Check input key length to MIN_BITS and MAX_BITS.
* doc/gcrypt.texi: Update supported Blowfish key lengths.
* tests/basic.c (check_ecb_cipher): New, with Blowfish test vectors
for different key lengths.
(check_cipher_modes): Call 'check_ecb_cipher'.
--

As noted by Peter Wu, Blowfish cipher implementation already supports key
lengths 8 to 576 bits [1]. This change updates documentation to reflect
that and adds new test vectors to check handling of different key lengths.

[1] https://lists.gnupg.org/pipermail/gcrypt-devel/2019-April/004680.html

Signed-off-by: Jussi Kivilinna <jussi.kivilinna@iki.fi>
cipher/blowfish.c
doc/gcrypt.texi
tests/basic.c

index ea6e64a..a1d81d3 100644 (file)
@@ -41,6 +41,8 @@
 #include "cipher-selftest.h"
 
 #define BLOWFISH_BLOCKSIZE 8
+#define BLOWFISH_KEY_MIN_BITS 8
+#define BLOWFISH_KEY_MAX_BITS 576
 
 
 /* USE_AMD64_ASM indicates whether to use AMD64 assembly code. */
@@ -1018,6 +1020,10 @@ do_bf_setkey (BLOWFISH_context *c, const byte *key, unsigned keylen)
   if( selftest_failed )
     return GPG_ERR_SELFTEST_FAILED;
 
+  if (keylen < BLOWFISH_KEY_MIN_BITS / 8 ||
+      keylen > BLOWFISH_KEY_MAX_BITS / 8)
+    return GPG_ERR_INV_KEYLEN;
+
   memset(hset, 0, sizeof(hset));
 
   for(i=0; i < 16+2; i++ )
index 8b765ba..d7bfa4c 100644 (file)
@@ -1538,7 +1538,7 @@ This is the IDEA algorithm.
 @cindex Triple-DES
 @cindex DES-EDE
 @cindex Digital Encryption Standard
-Triple-DES with 3 Keys as EDE.  The key size of this algorithm is 168 but
+Triple-DES with 3 Keys as EDE.  The key size of this algorithm is 168 bits but
 you have to pass 192 bits because the most significant bits of each byte
 are ignored.
 
@@ -1548,8 +1548,8 @@ CAST128-5 block cipher algorithm.  The key size is 128 bits.
 
 @item GCRY_CIPHER_BLOWFISH
 @cindex Blowfish
-The blowfish algorithm. The current implementation allows only for a key
-size of 128 bits.
+The blowfish algorithm. The supported key sizes are 8 to 576 bits in
+8 bit increments.
 
 @item GCRY_CIPHER_SAFER_SK128
 Reserved and not currently implemented.
index 3d6e8fc..3efd374 100644 (file)
@@ -447,6 +447,251 @@ check_aes128_cbc_cts_cipher (void)
 }
 
 static void
+check_ecb_cipher (void)
+{
+  /* ECB cipher check. Mainly for testing underlying block cipher. */
+  static const struct tv
+  {
+    int algo;
+    const char *key;
+    struct
+    {
+      const char *plaintext;
+      int keylen;
+      int inlen;
+      const char *out;
+    } data[MAX_DATA_LEN];
+  } tv[] =
+    {
+      /* Test vectors from OpenSSL for key lengths of 8 to 200 bits */
+      { GCRY_CIPHER_BLOWFISH,
+       "\xf0\xe1\xd2\xc3\xb4\xa5\x96\x87\x78\x69\x5a\x4b\x3c\x2d\x1e\x0f"
+       "\x00\x11\x22\x33\x44\x55\x66\x77\x88",
+       { { "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+           1,
+           8,
+           "\xf9\xad\x59\x7c\x49\xdb\x00\x5e" },
+         { "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+           2,
+           8,
+           "\xe9\x1d\x21\xc1\xd9\x61\xa6\xd6" },
+         { "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+           3,
+           8,
+           "\xe9\xc2\xb7\x0a\x1b\xc6\x5c\xf3" },
+         { "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+           4,
+           8,
+           "\xbe\x1e\x63\x94\x08\x64\x0f\x05" },
+         { "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+           5,
+           8,
+           "\xb3\x9e\x44\x48\x1b\xdb\x1e\x6e" },
+         { "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+           6,
+           8,
+           "\x94\x57\xaa\x83\xb1\x92\x8c\x0d" },
+         { "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+           7,
+           8,
+           "\x8b\xb7\x70\x32\xf9\x60\x62\x9d" },
+         { "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+           8,
+           8,
+           "\xe8\x7a\x24\x4e\x2c\xc8\x5e\x82" },
+         { "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+           9,
+           8,
+           "\x15\x75\x0e\x7a\x4f\x4e\xc5\x77" },
+         { "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+           10,
+           8,
+           "\x12\x2b\xa7\x0b\x3a\xb6\x4a\xe0" },
+         { "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+           11,
+           8,
+           "\x3a\x83\x3c\x9a\xff\xc5\x37\xf6" },
+         { "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+           12,
+           8,
+           "\x94\x09\xda\x87\xa9\x0f\x6b\xf2" },
+         { "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+           13,
+           8,
+           "\x88\x4f\x80\x62\x50\x60\xb8\xb4" },
+         { "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+           14,
+           8,
+           "\x1f\x85\x03\x1c\x19\xe1\x19\x68" },
+         { "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+           15,
+           8,
+           "\x79\xd9\x37\x3a\x71\x4c\xa3\x4f" },
+         { "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+           16,
+           8,
+           "\x93\x14\x28\x87\xee\x3b\xe1\x5c" },
+         { "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+           17,
+           8,
+           "\x03\x42\x9e\x83\x8c\xe2\xd1\x4b" },
+         { "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+           18,
+           8,
+           "\xa4\x29\x9e\x27\x46\x9f\xf6\x7b" },
+         { "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+           19,
+           8,
+           "\xaf\xd5\xae\xd1\xc1\xbc\x96\xa8" },
+         { "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+           20,
+           8,
+           "\x10\x85\x1c\x0e\x38\x58\xda\x9f" },
+         { "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+           21,
+           8,
+           "\xe6\xf5\x1e\xd7\x9b\x9d\xb2\x1f" },
+         { "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+           22,
+           8,
+           "\x64\xa6\xe1\x4a\xfd\x36\xb4\x6f" },
+         { "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+           23,
+           8,
+           "\x80\xc7\xd7\xd4\x5a\x54\x79\xad" },
+         { "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+           24,
+           8,
+           "\x05\x04\x4b\x62\xfa\x52\xd0\x80" },
+         { "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+           0, /* test default key length of 128-bits */
+           8,
+           "\x93\x14\x28\x87\xee\x3b\xe1\x5c" },
+         { }
+       }
+      },
+      /* Test vector from Linux kernel for key length of 448 bits */
+      { GCRY_CIPHER_BLOWFISH,
+       "\xf0\xe1\xd2\xc3\xb4\xa5\x96\x87\x78\x69\x5a\x4b\x3c\x2d\x1e\x0f"
+       "\x00\x11\x22\x33\x44\x55\x66\x77\x04\x68\x91\x04\xc2\xfd\x3b\x2f"
+       "\x58\x40\x23\x64\x1a\xba\x61\x76\x1f\x1f\x1f\x1f\x0e\x0e\x0e\x0e"
+       "\xff\xff\xff\xff\xff\xff\xff\xff",
+       { { "\xfe\xdc\xba\x98\x76\x54\x32\x10",
+           56,
+           8,
+           "\xc0\x45\x04\x01\x2e\x4e\x1f\x53" },
+         { }
+       }
+      },
+    };
+  gcry_cipher_hd_t hde, hdd;
+  unsigned char out[MAX_DATA_LEN];
+  int i, j, keylen, algo;
+  gcry_error_t err = 0;
+  gcry_error_t err2 = 0;
+
+  if (verbose)
+    fprintf (stderr, "  Starting ECB checks.\n");
+
+  for (i = 0; i < sizeof (tv) / sizeof (tv[0]); i++)
+    {
+      algo = tv[i].algo;
+
+      if (gcry_cipher_test_algo (algo) && in_fips_mode)
+       {
+         if (verbose)
+           fprintf (stderr, "  algorithm %d not available in fips mode\n",
+                    algo);
+         continue;
+       }
+
+      if (verbose)
+       fprintf (stderr, "    checking ECB mode for %s [%i]\n",
+                gcry_cipher_algo_name (algo),
+                algo);
+      err = gcry_cipher_open (&hde, algo, GCRY_CIPHER_MODE_ECB, 0);
+      if (!err)
+       err2 = gcry_cipher_open (&hdd, algo, GCRY_CIPHER_MODE_ECB, 0);
+      if (err || err2)
+       {
+         fail ("ecb-algo:%d-tv:%d, gcry_cipher_open failed: %s\n", algo, i,
+               gpg_strerror (err ? err : err2));
+         if (err2)
+           gcry_cipher_close (hde);
+         return;
+       }
+
+      for (j = 0; tv[i].data[j].inlen; j++)
+       {
+         keylen = tv[i].data[j].keylen;
+         if (!keylen)
+           {
+             keylen = gcry_cipher_get_algo_keylen(algo);
+             if (!keylen)
+               {
+                 fail ("ecb-algo:%d-tv:%d-data:%d, gcry_cipher_get_algo_keylen failed\n",
+                       algo, i, j);
+                 gcry_cipher_close (hde);
+                 gcry_cipher_close (hdd);
+                 return;
+               }
+           }
+
+         err = gcry_cipher_setkey (hde, tv[i].key, keylen);
+         if (!err)
+           err = gcry_cipher_setkey (hdd, tv[i].key, keylen);
+         if (err)
+           {
+             fail ("ecb-algo:%d-tv:%d-data:%d, gcry_cipher_setkey failed: %s\n",
+                   algo, i, j, gpg_strerror (err));
+             gcry_cipher_close (hde);
+             gcry_cipher_close (hdd);
+             return;
+           }
+
+         err = gcry_cipher_encrypt (hde, out, MAX_DATA_LEN,
+                                    tv[i].data[j].plaintext,
+                                    tv[i].data[j].inlen);
+         if (err)
+           {
+             fail ("ecb-algo:%d-tv:%d-data:%d, gcry_cipher_encrypt failed: %s\n",
+                   algo, 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 ("ecb-algo:%d-tv:%d-data:%d, encrypt mismatch entry\n",
+                   algo, i, j);
+           }
+
+         err = gcry_cipher_decrypt (hdd, out, tv[i].data[j].inlen, NULL, 0);
+         if (err)
+           {
+             fail ("ecb-algo:%d-tv:%d-data:%d, gcry_cipher_decrypt failed: %s\n",
+                   algo, 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 ("ecb-algo:%d-tv:%d-data:%d, decrypt mismatch entry\n",
+                   algo, i, j);
+           }
+       }
+
+      gcry_cipher_close (hde);
+      gcry_cipher_close (hdd);
+    }
+  if (verbose)
+    fprintf (stderr, "  Completed ECB checks.\n");
+}
+
+static void
 check_ctr_cipher (void)
 {
   static const struct tv
@@ -7916,6 +8161,7 @@ check_cipher_modes(void)
   if (verbose)
     fprintf (stderr, "Starting Cipher Mode checks.\n");
 
+  check_ecb_cipher ();
   check_aes128_cbc_cts_cipher ();
   check_cbc_mac_cipher ();
   check_ctr_cipher ();