Blowfish actually supports more than 128-bit keys
Peter Wu
peter at lekensteyn.nl
Wed Apr 10 00:18:10 CEST 2019
Hi,
The current cipher documentation[1] reports that GCRY_CIPHER_BLOWFISH
only supports 128-bit keys. In the long past, a "BLOWFISH160" variant
seems to have existed which supported 160-bit keys as reported through
gcry_cipher_get_algo_keylen.
One of our users would like to use Blowfish with 576 bit keys (don't
ask). Based on the documentation it would not be possible. The source
code (cipher/blowfish.c) however shows that do_bf_setkey function does
not limit the key size. In fact it is designed to support any number of
bytes (up to 72 bytes / 576 bits).
Could this be documented such that we can rely on it? Attached are two
test programs:
- One using test vectors from OpenSSL (key lengths 8..200 bits).
- One using Eric Young's test vector as linked by Schneier[2] (key
lengths 8..192 bits).
Rejecting key lengths above 576 bits (72 bytes) might be a good idea.
Rejecting 0 bytes would also be good to avoid a buffer overrun by one
byte. I have no idea why someone would like to use a very short key
though...
--
Kind regards,
Peter Wu
https://lekensteyn.nl
[1]: https://gnupg.org/documentation/manuals/gcrypt/Available-ciphers.html
[2]: https://www.schneier.com/academic/blowfish/
-------------- next part --------------
/* cc gcry-bf-test.c -lgcrypt && ./a.out */
#include <gcrypt.h>
// from openssl test/bftest.c
# define KEY_TEST_NUM 25
static unsigned char key_test[KEY_TEST_NUM] = {
0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87,
0x78, 0x69, 0x5a, 0x4b, 0x3c, 0x2d, 0x1e, 0x0f,
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
0x88
};
static unsigned char key_data[8] =
{ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 };
static unsigned char key_out[KEY_TEST_NUM][8] = {
{0xF9, 0xAD, 0x59, 0x7C, 0x49, 0xDB, 0x00, 0x5E},
{0xE9, 0x1D, 0x21, 0xC1, 0xD9, 0x61, 0xA6, 0xD6},
{0xE9, 0xC2, 0xB7, 0x0A, 0x1B, 0xC6, 0x5C, 0xF3},
{0xBE, 0x1E, 0x63, 0x94, 0x08, 0x64, 0x0F, 0x05},
{0xB3, 0x9E, 0x44, 0x48, 0x1B, 0xDB, 0x1E, 0x6E},
{0x94, 0x57, 0xAA, 0x83, 0xB1, 0x92, 0x8C, 0x0D},
{0x8B, 0xB7, 0x70, 0x32, 0xF9, 0x60, 0x62, 0x9D},
{0xE8, 0x7A, 0x24, 0x4E, 0x2C, 0xC8, 0x5E, 0x82},
{0x15, 0x75, 0x0E, 0x7A, 0x4F, 0x4E, 0xC5, 0x77},
{0x12, 0x2B, 0xA7, 0x0B, 0x3A, 0xB6, 0x4A, 0xE0},
{0x3A, 0x83, 0x3C, 0x9A, 0xFF, 0xC5, 0x37, 0xF6},
{0x94, 0x09, 0xDA, 0x87, 0xA9, 0x0F, 0x6B, 0xF2},
{0x88, 0x4F, 0x80, 0x62, 0x50, 0x60, 0xB8, 0xB4},
{0x1F, 0x85, 0x03, 0x1C, 0x19, 0xE1, 0x19, 0x68},
{0x79, 0xD9, 0x37, 0x3A, 0x71, 0x4C, 0xA3, 0x4F},
{0x93, 0x14, 0x28, 0x87, 0xEE, 0x3B, 0xE1, 0x5C},
{0x03, 0x42, 0x9E, 0x83, 0x8C, 0xE2, 0xD1, 0x4B},
{0xA4, 0x29, 0x9E, 0x27, 0x46, 0x9F, 0xF6, 0x7B},
{0xAF, 0xD5, 0xAE, 0xD1, 0xC1, 0xBC, 0x96, 0xA8},
{0x10, 0x85, 0x1C, 0x0E, 0x38, 0x58, 0xDA, 0x9F},
{0xE6, 0xF5, 0x1E, 0xD7, 0x9B, 0x9D, 0xB2, 0x1F},
{0x64, 0xA6, 0xE1, 0x4A, 0xFD, 0x36, 0xB4, 0x6F},
{0x80, 0xC7, 0xD7, 0xD4, 0x5A, 0x54, 0x79, 0xAD},
{0x05, 0x04, 0x4B, 0x62, 0xFA, 0x52, 0xD0, 0x80},
};
int main(void) {
gcry_cipher_hd_t hd;
gcry_error_t err;
err = gcry_cipher_open(&hd, GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_ECB, 0);
if (err != 0) {
printf("open: %s\n", gcry_strerror(err));
return 1;
}
for (unsigned i = 0; i < KEY_TEST_NUM - 1; i++) {
err = gcry_cipher_setkey(hd, key_test, i + 1);
if (err != 0) {
printf("setkey %d: %s\n", i, gcry_strerror(err));
goto end;
}
unsigned char out[8];
err = gcry_cipher_encrypt(hd, out, sizeof(out), key_data, sizeof(key_data));
if (err != 0) {
printf("decrypt %d: %s\n", i, gcry_strerror(err));
goto end;
}
if (memcmp(out, key_out[i], 8) != 0) {
printf("Test failure: %d\n", i);
goto end;
}
}
puts("Passed.");
end:
gcry_cipher_close(hd);
return err != 0;
}
-------------- next part --------------
/* cc gcry-bf-test.c -lgcrypt && ./a.out */
#include <gcrypt.h>
// test vectors from https://www.schneier.com/code/vectors.txt
# define KEY_TEST_NUM 24
static unsigned char key_test[KEY_TEST_NUM] = {
0xF0, 0xE1, 0xD2, 0xC3, 0xB4, 0xA5, 0x96, 0x87,
0x78, 0x69, 0x5A, 0x4B, 0x3C, 0x2D, 0x1E, 0x0F,
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77
};
static unsigned char key_data[8] = {
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10
};
static unsigned char key_out[KEY_TEST_NUM][8] = {
{ 0xF9, 0xAD, 0x59, 0x7C, 0x49, 0xDB, 0x00, 0x5E },
{ 0xE9, 0x1D, 0x21, 0xC1, 0xD9, 0x61, 0xA6, 0xD6 },
{ 0xE9, 0xC2, 0xB7, 0x0A, 0x1B, 0xC6, 0x5C, 0xF3 },
{ 0xBE, 0x1E, 0x63, 0x94, 0x08, 0x64, 0x0F, 0x05 },
{ 0xB3, 0x9E, 0x44, 0x48, 0x1B, 0xDB, 0x1E, 0x6E },
{ 0x94, 0x57, 0xAA, 0x83, 0xB1, 0x92, 0x8C, 0x0D },
{ 0x8B, 0xB7, 0x70, 0x32, 0xF9, 0x60, 0x62, 0x9D },
{ 0xE8, 0x7A, 0x24, 0x4E, 0x2C, 0xC8, 0x5E, 0x82 },
{ 0x15, 0x75, 0x0E, 0x7A, 0x4F, 0x4E, 0xC5, 0x77 },
{ 0x12, 0x2B, 0xA7, 0x0B, 0x3A, 0xB6, 0x4A, 0xE0 },
{ 0x3A, 0x83, 0x3C, 0x9A, 0xFF, 0xC5, 0x37, 0xF6 },
{ 0x94, 0x09, 0xDA, 0x87, 0xA9, 0x0F, 0x6B, 0xF2 },
{ 0x88, 0x4F, 0x80, 0x62, 0x50, 0x60, 0xB8, 0xB4 },
{ 0x1F, 0x85, 0x03, 0x1C, 0x19, 0xE1, 0x19, 0x68 },
{ 0x79, 0xD9, 0x37, 0x3A, 0x71, 0x4C, 0xA3, 0x4F },
{ 0x93, 0x14, 0x28, 0x87, 0xEE, 0x3B, 0xE1, 0x5C },
{ 0x03, 0x42, 0x9E, 0x83, 0x8C, 0xE2, 0xD1, 0x4B },
{ 0xA4, 0x29, 0x9E, 0x27, 0x46, 0x9F, 0xF6, 0x7B },
{ 0xAF, 0xD5, 0xAE, 0xD1, 0xC1, 0xBC, 0x96, 0xA8 },
{ 0x10, 0x85, 0x1C, 0x0E, 0x38, 0x58, 0xDA, 0x9F },
{ 0xE6, 0xF5, 0x1E, 0xD7, 0x9B, 0x9D, 0xB2, 0x1F },
{ 0x64, 0xA6, 0xE1, 0x4A, 0xFD, 0x36, 0xB4, 0x6F },
{ 0x80, 0xC7, 0xD7, 0xD4, 0x5A, 0x54, 0x79, 0xAD },
{ 0x05, 0x04, 0x4B, 0x62, 0xFA, 0x52, 0xD0, 0x80 }
};
int main(void) {
gcry_cipher_hd_t hd;
gcry_error_t err;
err = gcry_cipher_open(&hd, GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_ECB, 0);
if (err != 0) {
printf("open: %s\n", gcry_strerror(err));
return 1;
}
for (unsigned i = 0; i < KEY_TEST_NUM - 1; i++) {
err = gcry_cipher_setkey(hd, key_test, i + 1);
if (err != 0) {
printf("setkey %d: %s\n", i, gcry_strerror(err));
goto end;
}
unsigned char out[8];
err = gcry_cipher_encrypt(hd, out, sizeof(out), key_data, sizeof(key_data));
if (err != 0) {
printf("decrypt %d: %s\n", i, gcry_strerror(err));
goto end;
}
if (memcmp(out, key_out[i], 8) != 0) {
printf("Test failure: %d\n", i);
goto end;
}
}
puts("Passed.");
end:
gcry_cipher_close(hd);
return err != 0;
}
More information about the Gcrypt-devel
mailing list