diff options
author | Jussi Kivilinna <jussi.kivilinna@iki.fi> | 2022-05-08 22:02:30 +0300 |
---|---|---|
committer | Jussi Kivilinna <jussi.kivilinna@iki.fi> | 2022-05-11 20:14:33 +0300 |
commit | a9700956361d280746f2bffe94cbdb72c95eb3ed (patch) | |
tree | 2904eeba74f056890b54578097a17493107d0c69 /tests | |
parent | 9ab61ba24b72bc109b7578a7868716910d2ea9d1 (diff) | |
download | libgcrypt-a9700956361d280746f2bffe94cbdb72c95eb3ed.tar.gz |
cipher: move CBC/CFB/CTR self-tests to tests/basic
* cipher/Makefile.am: Remove 'cipher-selftest.c' and 'cipher-selftest.h'.
* cipher/cipher-selftest.c: Remove (refactor these tests to
tests/basic.c).
* cipher/cipher-selftest.h: Remove.
* cipher/blowfish.c (selftest_ctr, selftest_cbc, selftest_cfb): Remove.
(selftest): Remove CTR/CBC/CFB bulk self-tests.
* cipher/camellia-glue.c (selftest_ctr_128, selftest_cbc_128)
(selftest_cfb_128): Remove.
(selftest): Remove CTR/CBC/CFB bulk self-tests.
* cipher/cast5.c (selftest_ctr, selftest_cbc, selftest_cfb): Remove.
(selftest): Remove CTR/CBC/CFB bulk self-tests.
* cipher/des.c (bulk_selftest_setkey, selftest_ctr, selftest_cbc)
(selftest_cfb): Remove.
(selftest): Remove CTR/CBC/CFB bulk self-tests.
* cipher/rijndael.c (selftest_basic_128, selftest_basic_192)
(selftest_basic_256): Allocate context from stack instead of heap and
handle alignment manually.
(selftest_ctr_128, selftest_cbc_128, selftest_cfb_128): Remove.
(selftest): Remove CTR/CBC/CFB bulk self-tests.
* cipher/serpent.c (selftest_ctr_128, selftest_cbc_128)
(selftest_cfb_128): Remove.
(selftest): Remove CTR/CBC/CFB bulk self-tests.
* cipher/sm4.c (selftest_ctr_128, selftest_cbc_128)
(selftest_cfb_128): Remove.
(selftest): Remove CTR/CBC/CFB bulk self-tests.
* cipher/twofish.c (selftest_ctr, selftest_cbc, selftest_cfb): Remove.
(selftest): Remove CTR/CBC/CFB bulk self-tests.
* tests/basic.c (buf_xor, cipher_cbc_bulk_test, buf_xor_2dst)
(cipher_cfb_bulk_test, cipher_ctr_bulk_test): New.
(check_ciphers): Run cipher_cbc_bulk_test(), cipher_cfb_bulk_test() and
cipher_ctr_bulk_test() for block ciphers.
---
CBC/CFB/CTR bulk self-tests are quite computationally heavy and
slow down use cases where application opens cipher context once,
does processing and exits. Better place for these tests is in
`tests/basic`.
Signed-off-by: Jussi Kivilinna <jussi.kivilinna@iki.fi>
Diffstat (limited to 'tests')
-rw-r--r-- | tests/basic.c | 772 |
1 files changed, 772 insertions, 0 deletions
diff --git a/tests/basic.c b/tests/basic.c index 40a0a474..f5513740 100644 --- a/tests/basic.c +++ b/tests/basic.c @@ -27,6 +27,13 @@ #include <string.h> #include <stdarg.h> #include <assert.h> +#ifdef HAVE_STDINT_H +# include <stdint.h> /* uintptr_t */ +#elif defined(HAVE_INTTYPES_H) +# include <inttypes.h> +#else +/* In this case, uintptr_t is provided by config.h. */ +#endif #include "../src/gcrypt-int.h" @@ -11672,6 +11679,764 @@ out: +static void buf_xor(void *vdst, const void *vsrc1, const void *vsrc2, size_t len) +{ + char *dst = vdst; + const char *src1 = vsrc1; + const char *src2 = vsrc2; + + while (len) + { + *(char *)dst = *(char *)src1 ^ *(char *)src2; + dst++; + src1++; + src2++; + len--; + } +} + +/* Run the tests for <block cipher>-CBC-<block size>, tests bulk CBC + decryption. Returns NULL on success. */ +static int +cipher_cbc_bulk_test (int cipher_algo) +{ + const int nblocks = 128 - 1; + int i, offs; + int blocksize; + const char *cipher; + gcry_cipher_hd_t hd_one; + gcry_cipher_hd_t hd_cbc; + gcry_error_t err = 0; + unsigned char *plaintext, *plaintext2, *ciphertext, *iv, *iv2, *mem; + unsigned int memsize; + unsigned int keylen; + + static const unsigned char key[32] = { + 0x66,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F, + 0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x22, + 0x66,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F, + 0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x22 + }; + + if (gcry_cipher_test_algo (cipher_algo)) + return -1; + blocksize = gcry_cipher_get_algo_blklen(cipher_algo); + if (blocksize < 8) + return -1; + cipher = gcry_cipher_algo_name (cipher_algo); + keylen = gcry_cipher_get_algo_keylen (cipher_algo); + if (keylen > sizeof(key)) + { + fail ("%s-CBC-%d test failed (key too short)", cipher, blocksize * 8); + return -1; + } + + memsize = (blocksize * 2) + (blocksize * nblocks * 3) + 16; + + mem = xcalloc (1, memsize); + if (!mem) + return -1; + + offs = (16 - ((uintptr_t)mem & 15)) & 15; + iv = (void*)(mem + offs); + iv2 = iv + blocksize; + plaintext = iv2 + blocksize; + plaintext2 = plaintext + nblocks * blocksize; + ciphertext = plaintext2 + nblocks * blocksize; + + err = gcry_cipher_open (&hd_one, cipher_algo, GCRY_CIPHER_MODE_ECB, 0); + if (err) + { + xfree(mem); + fail ("%s-CBC-%d test failed (cipher open fail)", cipher, blocksize * 8); + return -1; + } + err = gcry_cipher_open (&hd_cbc, cipher_algo, GCRY_CIPHER_MODE_CBC, 0); + if (err) + { + gcry_cipher_close (hd_one); + xfree(mem); + fail ("%s-CBC-%d test failed (cipher open fail)", cipher, blocksize * 8); + return -1; + } + + /* Initialize ctx */ + if (gcry_cipher_setkey (hd_one, key, keylen) || + gcry_cipher_setkey (hd_cbc, key, keylen)) + { + gcry_cipher_close (hd_one); + gcry_cipher_close (hd_cbc); + xfree(mem); + fail ("%s-CBC-%d test failed (setkey fail)", cipher, blocksize * 8); + return -1; + } + + /* Test single block code path */ + memset (iv, 0x4e, blocksize); + memset (iv2, 0x4e, blocksize); + for (i = 0; i < blocksize; i++) + plaintext[i] = i; + + /* CBC manually. */ + buf_xor (ciphertext, iv, plaintext, blocksize); + err = gcry_cipher_encrypt (hd_one, ciphertext, blocksize, + ciphertext, blocksize); + if (err) + { + gcry_cipher_close (hd_one); + gcry_cipher_close (hd_cbc); + xfree(mem); + fail ("%s-CBC-%d test failed (ECB encrypt fail)", cipher, blocksize * 8); + return -1; + } + memcpy (iv, ciphertext, blocksize); + + /* CBC decrypt. */ + err = gcry_cipher_setiv (hd_cbc, iv2, blocksize); + if (err) + { + gcry_cipher_close (hd_one); + gcry_cipher_close (hd_cbc); + xfree(mem); + fail ("%s-CBC-%d test failed (setiv fail)", cipher, blocksize * 8); + return -1; + } + err = gcry_cipher_decrypt (hd_cbc, plaintext2, blocksize * 1, + ciphertext, blocksize * 1); + if (err) + { + gcry_cipher_close (hd_one); + gcry_cipher_close (hd_cbc); + xfree(mem); + fail ("%s-CBC-%d test failed (CBC decrypt fail)", cipher, blocksize * 8); + return -1; + } + + if (memcmp (plaintext2, plaintext, blocksize)) + { + gcry_cipher_close (hd_one); + gcry_cipher_close (hd_cbc); + xfree (mem); + fail ("%s-CBC-%d test failed (plaintext mismatch)", cipher, blocksize * 8); + return -1; + } + +#if 0 /* missing interface for reading IV */ + if (memcmp (iv2, iv, blocksize)) + { + gcry_cipher_close (hd_one); + gcry_cipher_close (hd_cbc); + xfree (mem); + fail ("%s-CBC-%d test failed (IV mismatch)", cipher, blocksize * 8); + return -1; + } +#endif + + /* Test parallelized code paths */ + memset (iv, 0x5f, blocksize); + memset (iv2, 0x5f, blocksize); + + for (i = 0; i < nblocks * blocksize; i++) + plaintext[i] = i; + + /* Create CBC ciphertext manually. */ + for (i = 0; i < nblocks * blocksize; i+=blocksize) + { + buf_xor (&ciphertext[i], iv, &plaintext[i], blocksize); + err = gcry_cipher_encrypt (hd_one, &ciphertext[i], blocksize, + &ciphertext[i], blocksize); + if (err) + { + gcry_cipher_close (hd_one); + gcry_cipher_close (hd_cbc); + xfree(mem); + fail ("%s-CBC-%d test failed (ECB encrypt fail)", cipher, blocksize * 8); + return -1; + } + memcpy (iv, &ciphertext[i], blocksize); + } + + /* Decrypt using bulk CBC and compare result. */ + err = gcry_cipher_setiv (hd_cbc, iv2, blocksize); + if (err) + { + gcry_cipher_close (hd_one); + gcry_cipher_close (hd_cbc); + xfree(mem); + fail ("%s-CBC-%d test failed (setiv fail)", cipher, blocksize * 8); + return -1; + } + err = gcry_cipher_decrypt (hd_cbc, plaintext2, blocksize * nblocks, + ciphertext, blocksize * nblocks); + if (err) + { + gcry_cipher_close (hd_one); + gcry_cipher_close (hd_cbc); + xfree(mem); + fail ("%s-CBC-%d test failed (CBC decrypt fail)", cipher, blocksize * 8); + return -1; + } + + if (memcmp (plaintext2, plaintext, nblocks * blocksize)) + { + gcry_cipher_close (hd_one); + gcry_cipher_close (hd_cbc); + xfree (mem); + fail ("%s-CBC-%d test failed (plaintext mismatch, parallel path)", + cipher, blocksize * 8); + return -1; + } +#if 0 /* missing interface for reading IV */ + if (memcmp (iv2, iv, blocksize)) + { + gcry_cipher_close (hd_one); + gcry_cipher_close (hd_cbc); + xfree (mem); + fail ("%s-CBC-%d test failed (IV mismatch, parallel path)", + cipher, blocksize * 8); + return -1; + } +#endif + + gcry_cipher_close (hd_one); + gcry_cipher_close (hd_cbc); + xfree (mem); + return -1; +} + + +static void +buf_xor_2dst(void *vdst1, void *vdst2, const void *vsrc, size_t len) +{ + byte *dst1 = vdst1; + byte *dst2 = vdst2; + const byte *src = vsrc; + + for (; len; len--) + *dst1++ = (*dst2++ ^= *src++); +} + +/* Run the tests for <block cipher>-CFB-<block size>, tests bulk CFB + decryption. Returns NULL on success. */ +static int +cipher_cfb_bulk_test (int cipher_algo) +{ + const int nblocks = 128 - 1; + int blocksize; + const char *cipher; + gcry_cipher_hd_t hd_one; + gcry_cipher_hd_t hd_cfb; + gcry_error_t err = 0; + int i, offs; + unsigned char *plaintext, *plaintext2, *ciphertext, *iv, *iv2, *mem; + unsigned int memsize; + unsigned int keylen; + + static const unsigned char key[32] = { + 0x11,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F, + 0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x33, + 0x11,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F, + 0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x33 + }; + + if (gcry_cipher_test_algo (cipher_algo)) + return -1; + blocksize = gcry_cipher_get_algo_blklen(cipher_algo); + if (blocksize < 8) + return -1; + cipher = gcry_cipher_algo_name (cipher_algo); + keylen = gcry_cipher_get_algo_keylen (cipher_algo); + if (keylen > sizeof(key)) + { + fail ("%s-CFB-%d test failed (key too short)", cipher, blocksize * 8); + return -1; + } + + memsize = (blocksize * 2) + (blocksize * nblocks * 3) + 16; + + mem = xcalloc (1, memsize); + if (!mem) + return -1; + + offs = (16 - ((uintptr_t)mem & 15)) & 15; + iv = (void*)(mem + offs); + iv2 = iv + blocksize; + plaintext = iv2 + blocksize; + plaintext2 = plaintext + nblocks * blocksize; + ciphertext = plaintext2 + nblocks * blocksize; + + err = gcry_cipher_open (&hd_one, cipher_algo, GCRY_CIPHER_MODE_ECB, 0); + if (err) + { + xfree(mem); + fail ("%s-CFB-%d test failed (cipher open fail)", cipher, blocksize * 8); + return -1; + } + err = gcry_cipher_open (&hd_cfb, cipher_algo, GCRY_CIPHER_MODE_CFB, 0); + if (err) + { + gcry_cipher_close (hd_one); + xfree(mem); + fail ("%s-CFB-%d test failed (cipher open fail)", cipher, blocksize * 8); + return -1; + } + + /* Initialize ctx */ + if (gcry_cipher_setkey (hd_one, key, keylen) || + gcry_cipher_setkey (hd_cfb, key, keylen)) + { + gcry_cipher_close (hd_one); + gcry_cipher_close (hd_cfb); + xfree(mem); + fail ("%s-CFB-%d test failed (setkey fail)", cipher, blocksize * 8); + return -1; + } + + /* Test single block code path */ + memset(iv, 0xd3, blocksize); + memset(iv2, 0xd3, blocksize); + for (i = 0; i < blocksize; i++) + plaintext[i] = i; + + /* CFB manually. */ + err = gcry_cipher_encrypt (hd_one, ciphertext, blocksize, iv, blocksize); + if (err) + { + gcry_cipher_close (hd_one); + gcry_cipher_close (hd_cfb); + xfree(mem); + fail ("%s-CFB-%d test failed (ECB encrypt fail)", cipher, blocksize * 8); + return -1; + } + buf_xor_2dst (iv, ciphertext, plaintext, blocksize); + + /* CFB decrypt. */ + err = gcry_cipher_setiv (hd_cfb, iv2, blocksize); + if (err) + { + gcry_cipher_close (hd_one); + gcry_cipher_close (hd_cfb); + xfree(mem); + fail ("%s-CFB-%d test failed (setiv fail)", cipher, blocksize * 8); + return -1; + } + err = gcry_cipher_decrypt (hd_cfb, plaintext2, blocksize * 1, + ciphertext, blocksize * 1); + if (err) + { + gcry_cipher_close (hd_one); + gcry_cipher_close (hd_cfb); + xfree(mem); + fail ("%s-CFB-%d test failed (CFB decrypt fail)", cipher, blocksize * 8); + return -1; + } + if (memcmp(plaintext2, plaintext, blocksize)) + { + gcry_cipher_close (hd_one); + gcry_cipher_close (hd_cfb); + xfree(mem); + fail ("%s-CFB-%d test failed (plaintext mismatch)", + cipher, blocksize * 8); + return -1; + } + +#if 0 + if (memcmp(iv2, iv, blocksize)) + { + gcry_cipher_close (hd_one); + gcry_cipher_close (hd_cfb); + xfree(mem); + fail ("%s-CFB-%d test failed (IV mismatch)", + cipher, blocksize * 8); + return -1; + } +#endif + + /* Test parallelized code paths */ + memset(iv, 0xe6, blocksize); + memset(iv2, 0xe6, blocksize); + + for (i = 0; i < nblocks * blocksize; i++) + plaintext[i] = i; + + /* Create CFB ciphertext manually. */ + for (i = 0; i < nblocks * blocksize; i+=blocksize) + { + err = gcry_cipher_encrypt (hd_one, &ciphertext[i], blocksize, + iv, blocksize); + if (err) + { + gcry_cipher_close (hd_one); + gcry_cipher_close (hd_cfb); + xfree(mem); + fail ("%s-CFB-%d test failed (ECB encrypt fail)", cipher, blocksize * 8); + return -1; + } + buf_xor_2dst (iv, &ciphertext[i], &plaintext[i], blocksize); + } + + /* Decrypt using bulk CBC and compare result. */ + err = gcry_cipher_setiv (hd_cfb, iv2, blocksize); + if (err) + { + gcry_cipher_close (hd_one); + gcry_cipher_close (hd_cfb); + xfree(mem); + fail ("%s-CFB-%d test failed (setiv fail)", cipher, blocksize * 8); + return -1; + } + err = gcry_cipher_decrypt (hd_cfb, plaintext2, blocksize * nblocks, + ciphertext, blocksize * nblocks); + if (err) + { + gcry_cipher_close (hd_one); + gcry_cipher_close (hd_cfb); + xfree(mem); + fail ("%s-CFB-%d test failed (CFB decrypt fail)", cipher, blocksize * 8); + return -1; + } + + if (memcmp(plaintext2, plaintext, nblocks * blocksize)) + { + gcry_cipher_close (hd_one); + gcry_cipher_close (hd_cfb); + xfree(mem); + fail ("%s-CFB-%d test failed (plaintext mismatch, parallel path)", + cipher, blocksize * 8); + return -1; + } +#if 0 + if (memcmp(iv2, iv, blocksize)) + { + gcry_cipher_close (hd_one); + gcry_cipher_close (hd_cfb); + xfree(mem); + fail ("%s-CFB-%d test failed (IV mismatch, parallel path)", + cipher, blocksize * 8); + return -1; + } +#endif + + gcry_cipher_close (hd_one); + gcry_cipher_close (hd_cfb); + xfree(mem); + return -1; +} + + +/* Run the tests for <block cipher>-CTR-<block size>, tests IV increment + of bulk CTR encryption. Returns NULL on success. */ +static int +cipher_ctr_bulk_test (int cipher_algo) +{ + const int nblocks = 128 - 1; + int blocksize; + const char *cipher; + gcry_cipher_hd_t hd_one; + gcry_cipher_hd_t hd_ctr; + gcry_error_t err = 0; + int i, j, offs, diff; + unsigned char *plaintext, *plaintext2, *ciphertext, *ciphertext2, + *iv, *iv2, *mem; + unsigned int memsize; + unsigned int keylen; + + static const unsigned char key[32] = { + 0x06,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F, + 0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x21, + 0x06,0x9A,0x00,0x7F,0xC7,0x6A,0x45,0x9F, + 0x98,0xBA,0xF9,0x17,0xFE,0xDF,0x95,0x21 + }; + + if (gcry_cipher_test_algo (cipher_algo)) + return -1; + blocksize = gcry_cipher_get_algo_blklen(cipher_algo); + if (blocksize < 8) + return -1; + cipher = gcry_cipher_algo_name (cipher_algo); + keylen = gcry_cipher_get_algo_keylen (cipher_algo); + if (keylen > sizeof(key)) + { + fail ("%s-CTR-%d test failed (key too short)", cipher, blocksize * 8); + return -1; + } + + memsize = (blocksize * 2) + (blocksize * nblocks * 4) + 16; + + mem = xcalloc (1, memsize); + if (!mem) + return -1; + + offs = (16 - ((uintptr_t)mem & 15)) & 15; + iv = (void*)(mem + offs); + iv2 = iv + blocksize; + plaintext = iv2 + blocksize; + plaintext2 = plaintext + nblocks * blocksize; + ciphertext = plaintext2 + nblocks * blocksize; + ciphertext2 = ciphertext + nblocks * blocksize; + + err = gcry_cipher_open (&hd_one, cipher_algo, GCRY_CIPHER_MODE_ECB, 0); + if (err) + { + xfree(mem); + fail ("%s-CTR-%d test failed (cipher open fail)", cipher, blocksize * 8); + return -1; + } + err = gcry_cipher_open (&hd_ctr, cipher_algo, GCRY_CIPHER_MODE_CTR, 0); + if (err) + { + gcry_cipher_close (hd_one); + xfree(mem); + fail ("%s-CTR-%d test failed (cipher open fail)", cipher, blocksize * 8); + return -1; + } + + /* Initialize ctx */ + if (gcry_cipher_setkey (hd_one, key, keylen) || + gcry_cipher_setkey (hd_ctr, key, keylen)) + { + gcry_cipher_close (hd_one); + gcry_cipher_close (hd_ctr); + xfree(mem); + fail ("%s-CTR-%d test failed (setkey fail)", cipher, blocksize * 8); + return -1; + } + + /* Test single block code path */ + memset (iv, 0xff, blocksize); + for (i = 0; i < blocksize; i++) + plaintext[i] = i; + + /* CTR manually. */ + err = gcry_cipher_encrypt (hd_one, ciphertext, blocksize, iv, blocksize); + if (err) + { + gcry_cipher_close (hd_one); + gcry_cipher_close (hd_ctr); + xfree(mem); + fail ("%s-CTR-%d test failed (ECB encrypt fail)", cipher, blocksize * 8); + return -1; + } + for (i = 0; i < blocksize; i++) + ciphertext[i] ^= plaintext[i]; + for (i = blocksize; i > 0; i--) + { + iv[i-1]++; + if (iv[i-1]) + break; + } + + memset (iv2, 0xff, blocksize); + err = gcry_cipher_setctr (hd_ctr, iv2, blocksize); + if (err) + { + gcry_cipher_close (hd_one); + gcry_cipher_close (hd_ctr); + xfree(mem); + fail ("%s-CTR-%d test failed (setiv fail)", cipher, blocksize * 8); + return -1; + } + err = gcry_cipher_encrypt (hd_ctr, plaintext2, blocksize * 1, + ciphertext, blocksize * 1); + if (err) + { + gcry_cipher_close (hd_one); + gcry_cipher_close (hd_ctr); + xfree(mem); + fail ("%s-CTR-%d test failed (CTR encrypt fail)", cipher, blocksize * 8); + return -1; + } + + if (memcmp (plaintext2, plaintext, blocksize)) + { + gcry_cipher_close (hd_one); + gcry_cipher_close (hd_ctr); + xfree(mem); + fail ("%s-CTR-%d test failed (plaintext mismatch)", + cipher, blocksize * 8); + return -1; + } + +#if 0 + if (memcmp (iv2, iv, blocksize)) + { + gcry_cipher_close (hd_one); + gcry_cipher_close (hd_ctr); + xfree(mem); + fail ("%s-CTR-%d test failed (IV mismatch)", cipher, blocksize * 8); + return -1; + } +#endif + + /* Test bulk encryption with typical IV. */ + memset(iv, 0x57, blocksize-4); + iv[blocksize-1] = 1; + iv[blocksize-2] = 0; + iv[blocksize-3] = 0; + iv[blocksize-4] = 0; + memset(iv2, 0x57, blocksize-4); + iv2[blocksize-1] = 1; + iv2[blocksize-2] = 0; + iv2[blocksize-3] = 0; + iv2[blocksize-4] = 0; + + for (i = 0; i < blocksize * nblocks; i++) + plaintext2[i] = plaintext[i] = i; + + /* Create CTR ciphertext manually. */ + for (i = 0; i < blocksize * nblocks; i+=blocksize) + { + err = gcry_cipher_encrypt (hd_one, &ciphertext[i], blocksize, + iv, blocksize); + if (err) + { + gcry_cipher_close (hd_one); + gcry_cipher_close (hd_ctr); + xfree(mem); + fail ("%s-CTR-%d test failed (ECB encrypt fail)", + cipher, blocksize * 8); + return -1; + } + for (j = 0; j < blocksize; j++) + ciphertext[i+j] ^= plaintext[i+j]; + for (j = blocksize; j > 0; j--) + { + iv[j-1]++; + if (iv[j-1]) + break; + } + } + + err = gcry_cipher_setctr (hd_ctr, iv2, blocksize); + if (err) + { + gcry_cipher_close (hd_one); + gcry_cipher_close (hd_ctr); + xfree(mem); + fail ("%s-CTR-%d test failed (setiv fail)", cipher, blocksize * 8); + return -1; + } + err = gcry_cipher_encrypt (hd_ctr, ciphertext2, blocksize * nblocks, + plaintext2, blocksize * nblocks); + if (err) + { + gcry_cipher_close (hd_one); + gcry_cipher_close (hd_ctr); + xfree(mem); + fail ("%s-CTR-%d test failed (CTR encrypt fail)", cipher, blocksize * 8); + return -1; + } + + if (memcmp (ciphertext2, ciphertext, blocksize * nblocks)) + { + gcry_cipher_close (hd_one); + gcry_cipher_close (hd_ctr); + xfree(mem); + fail ("%s-CTR-%d test failed (ciphertext mismatch, bulk)", + cipher, blocksize * 8); + return -1; + } +#if 0 + if (memcmp (iv2, iv, blocksize)) + { + gcry_cipher_close (hd_one); + gcry_cipher_close (hd_ctr); + xfree(mem); + fail ("%s-CTR-%d test failed (IV mismatch, bulk)", cipher, blocksize * 8); + return -1; + } +#endif + + /* Test parallelized code paths (check counter overflow handling) */ + for (diff = 0; diff < nblocks; diff++) { + memset(iv, 0xff, blocksize); + iv[blocksize-1] -= diff; + iv[0] = iv[1] = 0; + iv[2] = 0x07; + + for (i = 0; i < blocksize * nblocks; i++) + plaintext[i] = i; + + /* Create CTR ciphertext manually. */ + for (i = 0; i < blocksize * nblocks; i+=blocksize) + { + err = gcry_cipher_encrypt (hd_one, &ciphertext[i], blocksize, + iv, blocksize); + if (err) + { + gcry_cipher_close (hd_one); + gcry_cipher_close (hd_ctr); + xfree(mem); + fail ("%s-CTR-%d test failed (ECB encrypt fail)", + cipher, blocksize * 8); + return -1; + } + for (j = 0; j < blocksize; j++) + ciphertext[i+j] ^= plaintext[i+j]; + for (j = blocksize; j > 0; j--) + { + iv[j-1]++; + if (iv[j-1]) + break; + } + } + + /* Decrypt using bulk CTR and compare result. */ + memset(iv2, 0xff, blocksize); + iv2[blocksize-1] -= diff; + iv2[0] = iv2[1] = 0; + iv2[2] = 0x07; + + err = gcry_cipher_setctr (hd_ctr, iv2, blocksize); + if (err) + { + gcry_cipher_close (hd_one); + gcry_cipher_close (hd_ctr); + xfree(mem); + fail ("%s-CTR-%d test failed (setiv fail)", cipher, blocksize * 8); + return -1; + } + err = gcry_cipher_decrypt (hd_ctr, plaintext2, blocksize * nblocks, + ciphertext, blocksize * nblocks); + if (err) + { + gcry_cipher_close (hd_one); + gcry_cipher_close (hd_ctr); + xfree(mem); + fail ("%s-CTR-%d test failed (CTR decrypt fail)", cipher, blocksize * 8); + return -1; + } + + if (memcmp (plaintext2, plaintext, blocksize * nblocks)) + { + gcry_cipher_close (hd_one); + gcry_cipher_close (hd_ctr); + xfree(mem); + fail ("%s-CTR-%d test failed (plaintext mismatch, diff: %d)", + cipher, blocksize * 8, diff); + return -1; + } +#if 0 + if (memcmp(iv2, iv, blocksize)) + { + gcry_cipher_close (hd_one); + gcry_cipher_close (hd_ctr); + xfree(mem); + fail ("%s-CTR-%d test failed (IV mismatch, diff: %d)", + cipher, blocksize * 8, diff); + return -1; + } +#endif + } + + gcry_cipher_close (hd_one); + gcry_cipher_close (hd_ctr); + xfree(mem); + return -1; +} + + + static void check_ciphers (void) { @@ -11784,6 +12549,13 @@ check_ciphers (void) check_one_cipher (algos[i], GCRY_CIPHER_MODE_OCB, 0); if (gcry_cipher_get_algo_blklen (algos[i]) == GCRY_XTS_BLOCK_LEN) check_one_cipher (algos[i], GCRY_CIPHER_MODE_XTS, 0); + + if (gcry_cipher_get_algo_blklen (algos[i]) >= 8) + { + cipher_cbc_bulk_test (algos[i]); + cipher_cfb_bulk_test (algos[i]); + cipher_ctr_bulk_test (algos[i]); + } } for (i = 0; algos2[i]; i++) |