summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJussi Kivilinna <jussi.kivilinna@iki.fi>2019-04-18 18:53:35 +0300
committerJussi Kivilinna <jussi.kivilinna@iki.fi>2019-04-18 18:53:35 +0300
commit3546599e5578f89f9e77b08bf599f9c44b23da5f (patch)
tree0c992941e7d2a1b1f00d5df9cf5c0a09c00b05c6
parentd11ae95d05dc39ec6b825d1109afadd964589880 (diff)
downloadlibgcrypt-3546599e5578f89f9e77b08bf599f9c44b23da5f.tar.gz
Limit and document Blowfish key lengths to 8-576 bits
* 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>
-rw-r--r--cipher/blowfish.c6
-rw-r--r--doc/gcrypt.texi6
-rw-r--r--tests/basic.c246
3 files changed, 255 insertions, 3 deletions
diff --git a/cipher/blowfish.c b/cipher/blowfish.c
index ea6e64a7..a1d81d31 100644
--- a/cipher/blowfish.c
+++ b/cipher/blowfish.c
@@ -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++ )
diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi
index 8b765ba8..d7bfa4c2 100644
--- a/doc/gcrypt.texi
+++ b/doc/gcrypt.texi
@@ -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.
diff --git a/tests/basic.c b/tests/basic.c
index 3d6e8fc1..3efd3744 100644
--- a/tests/basic.c
+++ b/tests/basic.c
@@ -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 ();