diff options
-rw-r--r-- | AUTHORS | 13 | ||||
-rw-r--r-- | TODO | 3 | ||||
-rw-r--r-- | cipher/ChangeLog | 5 | ||||
-rw-r--r-- | cipher/cipher.c | 101 | ||||
-rw-r--r-- | doc/ChangeLog | 5 | ||||
-rw-r--r-- | doc/gcrypt.texi | 12 | ||||
-rw-r--r-- | tests/ChangeLog | 9 | ||||
-rw-r--r-- | tests/basic.c | 414 | ||||
-rw-r--r-- | tests/benchmark.c | 1 |
9 files changed, 544 insertions, 19 deletions
@@ -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 @@ -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 + diff --git a/cipher/ChangeLog b/cipher/ChangeLog index c70ebcab..792bd82a 100644 --- a/cipher/ChangeLog +++ b/cipher/ChangeLog @@ -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 diff --git a/cipher/cipher.c b/cipher/cipher.c index 087a3478..03b17525 100644 --- a/cipher/cipher.c +++ b/cipher/cipher.c @@ -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; diff --git a/doc/ChangeLog b/doc/ChangeLog index 797396d0..e0b54115 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -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. diff --git a/doc/gcrypt.texi b/doc/gcrypt.texi index 907f7bb2..fa32a3ab 100644 --- a/doc/gcrypt.texi +++ b/doc/gcrypt.texi @@ -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. diff --git a/tests/ChangeLog b/tests/ChangeLog index bd86b5f4..4d78663e 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -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. diff --git a/tests/basic.c b/tests/basic.c index f5444dc2..29e0054e 100644 --- a/tests/basic.c +++ b/tests/basic.c @@ -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 (); diff --git a/tests/benchmark.c b/tests/benchmark.c index 04cfedc9..1d82c5d8 100644 --- a/tests/benchmark.c +++ b/tests/benchmark.c @@ -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} |