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