From 1c2135506825ae80966fe2797613806916b7e3c0 Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Wed, 6 Nov 2019 12:07:24 +0100 Subject: [PATCH 1/2] nettle: backport fixes to cfb8_decrypt cfb8: don't truncate output IV if input is shorter than block size: https://git.lysator.liu.se/nettle/nettle/commit/f4a9c842621baf5d71aa9cc3989851f44dc46861 Signed-off-by: Daiki Ueno --- lib/nettle/backport/cfb8.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/nettle/backport/cfb8.c b/lib/nettle/backport/cfb8.c index e9816feb7..1762192f4 100644 --- a/lib/nettle/backport/cfb8.c +++ b/lib/nettle/backport/cfb8.c @@ -110,10 +110,12 @@ cfb8_decrypt(const void *ctx, nettle_cipher_func *f, src += i; dst += i; - memcpy(buffer, buffer + block_size, block_size); - memcpy(buffer + block_size, src, - length < block_size ? length : block_size); - + if (i == block_size) + { + memcpy(buffer, buffer + block_size, block_size); + memcpy(buffer + block_size, src, + length < block_size ? length : block_size); + } } memcpy(iv, buffer + i, block_size); -- 2.21.0 From cc01347302678719f0bcfb4f3383fe0f1e905ed8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=BCnther=20Deschner?= Date: Wed, 6 Nov 2019 13:17:57 +0100 Subject: [PATCH 2/2] crypto-selftests: test CFB8 ciphers with different chunksizes Signed-off-by: Guenther Deschner Signed-off-by: Daiki Ueno --- lib/crypto-selftests.c | 124 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 118 insertions(+), 6 deletions(-) diff --git a/lib/crypto-selftests.c b/lib/crypto-selftests.c index 6caf817e8..5f0a4ec8b 100644 --- a/lib/crypto-selftests.c +++ b/lib/crypto-selftests.c @@ -710,6 +710,107 @@ static int test_cipher(gnutls_cipher_algorithm_t cipher, return 0; } +static int test_cipher_all_block_sizes(gnutls_cipher_algorithm_t cipher, + const struct cipher_vectors_st *vectors, + size_t vectors_size, unsigned flags) +{ + gnutls_cipher_hd_t hd; + int ret; + unsigned int i; + uint8_t tmp[384]; + gnutls_datum_t key, iv = {NULL, 0}; + size_t block; + size_t offset; + + for (i = 0; i < vectors_size; i++) { + for (block = 1; block <= vectors[i].plaintext_size; block++) { + key.data = (void *) vectors[i].key; + key.size = vectors[i].key_size; + + iv.data = (void *) vectors[i].iv; + iv.size = gnutls_cipher_get_iv_size(cipher); + + if (iv.size != vectors[i].iv_size) + return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR); + + ret = gnutls_cipher_init(&hd, cipher, &key, &iv); + if (ret < 0) { + _gnutls_debug_log("error initializing: %s\n", + gnutls_cipher_get_name(cipher)); + return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR); + } + + for (offset = 0; + offset < vectors[i].plaintext_size; + offset += block) { + ret = + gnutls_cipher_encrypt2(hd, + vectors[i].plaintext + offset, + MIN(block, vectors[i].plaintext_size - offset), + tmp + offset, + sizeof(tmp) - offset); + if (ret < 0) + return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR); + } + + if (memcmp + (tmp, vectors[i].ciphertext, + vectors[i].plaintext_size) != 0) { + _gnutls_debug_log("%s encryption of test vector %d failed with block size %d/%d!\n", + gnutls_cipher_get_name(cipher), + i, (int)block, (int)vectors[i].plaintext_size); + return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR); + } + + gnutls_cipher_deinit(hd); + } + } + + for (i = 0; i < vectors_size; i++) { + for (block = 1; block <= vectors[i].plaintext_size; block++) { + key.data = (void *) vectors[i].key; + key.size = vectors[i].key_size; + + iv.data = (void *) vectors[i].iv; + iv.size = gnutls_cipher_get_iv_size(cipher); + + ret = gnutls_cipher_init(&hd, cipher, &key, &iv); + if (ret < 0) + return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR); + + for (offset = 0; + offset + block <= vectors[i].plaintext_size; + offset += block) { + ret = + gnutls_cipher_decrypt2(hd, + vectors[i].ciphertext + offset, + MIN(block, vectors[i].plaintext_size - offset), + tmp + offset, + sizeof(tmp) - offset); + if (ret < 0) + return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR); + } + + if (memcmp + (tmp, vectors[i].plaintext, + vectors[i].plaintext_size) != 0) { + _gnutls_debug_log("%s decryption of test vector %d failed with block size %d!\n", + gnutls_cipher_get_name(cipher), + i, (int)block); + return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR); + } + + gnutls_cipher_deinit(hd); + } + } + + _gnutls_debug_log + ("%s self check succeeded\n", + gnutls_cipher_get_name(cipher)); + + return 0; +} + /* AEAD modes (compat APIs) */ static int test_cipher_aead_compat(gnutls_cipher_algorithm_t cipher, const struct cipher_aead_vectors_st *vectors, @@ -1721,6 +1822,14 @@ static int test_mac(gnutls_mac_algorithm_t mac, if (!(flags & GNUTLS_SELF_TEST_FLAG_ALL) || ret < 0) \ return ret +#define CASE2(x, func, func2, vectors) case x: \ + ret = func(x, V(vectors), flags); \ + if (!(flags & GNUTLS_SELF_TEST_FLAG_ALL) || ret < 0) \ + return ret; \ + ret = func2(x, V(vectors), flags); \ + if (!(flags & GNUTLS_SELF_TEST_FLAG_ALL) || ret < 0) \ + return ret + #define NON_FIPS_CASE(x, func, vectors) case x: \ if (_gnutls_fips_mode_enabled() == 0) { \ ret = func(x, V(vectors), flags); \ @@ -1786,14 +1895,17 @@ int gnutls_cipher_self_test(unsigned flags, gnutls_cipher_algorithm_t cipher) NON_FIPS_CASE(GNUTLS_CIPHER_CHACHA20_POLY1305, test_cipher_aead, chacha_poly1305_vectors); FALLTHROUGH; - CASE(GNUTLS_CIPHER_AES_128_CFB8, test_cipher, - aes128_cfb8_vectors); + CASE2(GNUTLS_CIPHER_AES_128_CFB8, test_cipher, + test_cipher_all_block_sizes, + aes128_cfb8_vectors); FALLTHROUGH; - CASE(GNUTLS_CIPHER_AES_192_CFB8, test_cipher, - aes192_cfb8_vectors); + CASE2(GNUTLS_CIPHER_AES_192_CFB8, test_cipher, + test_cipher_all_block_sizes, + aes192_cfb8_vectors); FALLTHROUGH; - CASE(GNUTLS_CIPHER_AES_256_CFB8, test_cipher, - aes256_cfb8_vectors); + CASE2(GNUTLS_CIPHER_AES_256_CFB8, test_cipher, + test_cipher_all_block_sizes, + aes256_cfb8_vectors); FALLTHROUGH; CASE(GNUTLS_CIPHER_AES_128_XTS, test_cipher, aes128_xts_vectors); -- 2.21.0