From 940143cccea91fdc41f9a052ee2b64ecbd3a5dac Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Wed, 24 Oct 2018 12:14:51 -0400 Subject: Add AES-CFB8 Support Signed-off-by: Simo Sorce --- lib/includes/gnutls/gnutls.h.in | 6 +++++ lib/nettle/cipher.c | 58 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in index a5439cce56..786dcdf055 100644 --- a/lib/includes/gnutls/gnutls.h.in +++ b/lib/includes/gnutls/gnutls.h.in @@ -97,6 +97,9 @@ extern "C" { * @GNUTLS_CIPHER_AES_128_CBC: AES in CBC mode with 128-bit keys. * @GNUTLS_CIPHER_AES_192_CBC: AES in CBC mode with 192-bit keys. * @GNUTLS_CIPHER_AES_256_CBC: AES in CBC mode with 256-bit keys. + * @GNUTLS_CIPHER_AES_128_CFB8: AES in CFB8 mode with 128-bit keys. + * @GNUTLS_CIPHER_AES_192_CFB8: AES in CFB8 mode with 192-bit keys. + * @GNUTLS_CIPHER_AES_256_CFB8: AES in CFB8 mode with 256-bit keys. * @GNUTLS_CIPHER_ARCFOUR_40: ARCFOUR stream cipher with 40-bit keys. * @GNUTLS_CIPHER_CAMELLIA_128_CBC: Camellia in CBC mode with 128-bit keys. * @GNUTLS_CIPHER_CAMELLIA_192_CBC: Camellia in CBC mode with 192-bit keys. @@ -161,6 +164,9 @@ typedef enum gnutls_cipher_algorithm { GNUTLS_CIPHER_GOST28147_CPB_CFB = 26, GNUTLS_CIPHER_GOST28147_CPC_CFB = 27, GNUTLS_CIPHER_GOST28147_CPD_CFB = 28, + GNUTLS_CIPHER_AES_128_CFB8 = 29, + GNUTLS_CIPHER_AES_192_CFB8 = 30, + GNUTLS_CIPHER_AES_256_CFB8 = 31, /* used only for PGP internals. Ignored in TLS/SSL */ diff --git a/lib/nettle/cipher.c b/lib/nettle/cipher.c index 24ecf8ded3..0f6c737d6f 100644 --- a/lib/nettle/cipher.c +++ b/lib/nettle/cipher.c @@ -43,6 +43,7 @@ #include #include #include +#include #include struct nettle_cipher_ctx; @@ -258,6 +259,24 @@ static void _des3_set_key(struct des3_ctx *ctx, const uint8_t *key) des3_set_key(ctx, key); } +static void +_cfb8_encrypt(struct nettle_cipher_ctx *ctx, size_t length, uint8_t * dst, + const uint8_t * src) +{ + cfb8_encrypt(ctx->ctx_ptr, ctx->cipher->encrypt_block, + ctx->iv_size, ctx->iv, + length, dst, src); +} + +static void +_cfb8_decrypt(struct nettle_cipher_ctx *ctx, size_t length, uint8_t * dst, + const uint8_t * src) +{ + cfb8_decrypt(ctx->ctx_ptr, ctx->cipher->encrypt_block, + ctx->iv_size, ctx->iv, + length, dst, src); +} + static const struct nettle_cipher_st builtin_ciphers[] = { { .algo = GNUTLS_CIPHER_AES_128_GCM, .block_size = AES_BLOCK_SIZE, @@ -616,6 +635,45 @@ static const struct nettle_cipher_st builtin_ciphers[] = { .set_decrypt_key = _gost28147_set_key_cpd, }, #endif + { .algo = GNUTLS_CIPHER_AES_128_CFB8, + .block_size = AES_BLOCK_SIZE, + .key_size = AES128_KEY_SIZE, + .encrypt_block = (nettle_cipher_func*)aes128_encrypt, + .decrypt_block = (nettle_cipher_func*)aes128_encrypt, + + .ctx_size = sizeof(struct CFB8_CTX(struct aes128_ctx, AES_BLOCK_SIZE)), + .encrypt = _cfb8_encrypt, + .decrypt = _cfb8_decrypt, + .set_encrypt_key = (nettle_set_key_func*)aes128_set_encrypt_key, + .set_decrypt_key = (nettle_set_key_func*)aes128_set_encrypt_key, + .max_iv_size = AES_BLOCK_SIZE, + }, + { .algo = GNUTLS_CIPHER_AES_192_CFB8, + .block_size = AES_BLOCK_SIZE, + .key_size = AES192_KEY_SIZE, + .encrypt_block = (nettle_cipher_func*)aes192_encrypt, + .decrypt_block = (nettle_cipher_func*)aes192_encrypt, + + .ctx_size = sizeof(struct CFB8_CTX(struct aes192_ctx, AES_BLOCK_SIZE)), + .encrypt = _cfb8_encrypt, + .decrypt = _cfb8_decrypt, + .set_encrypt_key = (nettle_set_key_func*)aes192_set_encrypt_key, + .set_decrypt_key = (nettle_set_key_func*)aes192_set_encrypt_key, + .max_iv_size = AES_BLOCK_SIZE, + }, + { .algo = GNUTLS_CIPHER_AES_256_CFB8, + .block_size = AES_BLOCK_SIZE, + .key_size = AES256_KEY_SIZE, + .encrypt_block = (nettle_cipher_func*)aes256_encrypt, + .decrypt_block = (nettle_cipher_func*)aes256_encrypt, + + .ctx_size = sizeof(struct CFB8_CTX(struct aes256_ctx, AES_BLOCK_SIZE)), + .encrypt = _cfb8_encrypt, + .decrypt = _cfb8_decrypt, + .set_encrypt_key = (nettle_set_key_func*)aes256_set_encrypt_key, + .set_decrypt_key = (nettle_set_key_func*)aes256_set_encrypt_key, + .max_iv_size = AES_BLOCK_SIZE, + }, }; static int wrap_nettle_cipher_exists(gnutls_cipher_algorithm_t algo) -- cgit v1.2.1 From 2e30163b1fda16ae1e7373458f1cbbce96fe4a6b Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Wed, 24 Oct 2018 13:04:22 -0400 Subject: Vendor in CFB8 functionality from Nettle If nettle's CFB8 is not available, use a vendored in version from master. This is necessary as long as we need to link against 3.4 for ABI compatibility reasons. Signed-off-by: Simo Sorce --- configure.ac | 6 +++ lib/nettle/Makefile.am | 2 + lib/nettle/backport/cfb8.c | 117 +++++++++++++++++++++++++++++++++++++++++++++ lib/nettle/backport/cfb8.h | 96 +++++++++++++++++++++++++++++++++++++ lib/nettle/cipher.c | 5 +- 5 files changed, 225 insertions(+), 1 deletion(-) create mode 100644 lib/nettle/backport/cfb8.c create mode 100644 lib/nettle/backport/cfb8.h diff --git a/configure.ac b/configure.ac index 95c756e8bd..7b50f548d2 100644 --- a/configure.ac +++ b/configure.ac @@ -559,6 +559,12 @@ if test "$enable_non_suiteb" = "yes";then fi AM_CONDITIONAL(ENABLE_NON_SUITEB_CURVES, test "$enable_non_suiteb" = "yes") +# Check if nettle has CFB8 support +save_LIBS=$LIBS +LIBS="$LIBS $NETTLE_LIBS" +AC_CHECK_FUNCS(nettle_cfb8_encrypt) +LIBS=$save_LIBS + AC_MSG_CHECKING([whether to build libdane]) AC_ARG_ENABLE(libdane, AS_HELP_STRING([--disable-libdane], diff --git a/lib/nettle/Makefile.am b/lib/nettle/Makefile.am index bd5ec45901..7bb88b8c8f 100644 --- a/lib/nettle/Makefile.am +++ b/lib/nettle/Makefile.am @@ -24,6 +24,7 @@ AM_CFLAGS += $(HOGWEED_CFLAGS) $(GMP_CFLAGS) AM_CPPFLAGS = \ -I$(srcdir)/int \ + -I$(srcdir)/backport \ -I$(srcdir)/../../gl \ -I$(builddir)/../../gl \ -I$(srcdir)/../includes \ @@ -39,6 +40,7 @@ noinst_LTLIBRARIES = libcrypto.la libcrypto_la_SOURCES = pk.c mpi.c mac.c cipher.c init.c \ gnettle.h rnd-common.h prf.c \ + backport/cfb8.c backport/cfb8.h \ rnd.c int/rsa-fips.h int/rsa-keygen-fips186.c int/provable-prime.c \ int/dsa-fips.h int/dsa-keygen-fips186.c int/dsa-validate.c \ int/tls1-prf.c int/tls1-prf.h diff --git a/lib/nettle/backport/cfb8.c b/lib/nettle/backport/cfb8.c new file mode 100644 index 0000000000..30e48322fd --- /dev/null +++ b/lib/nettle/backport/cfb8.c @@ -0,0 +1,117 @@ +/* backport of cfb.c for CFB8 + + Cipher feedback mode. + + Copyright (C) 2015, 2017 Dmitry Eremin-Solenikov + Copyright (C) 2001, 2011 Niels Möller + + This file is part of GNU Nettle. + + GNU Nettle is free software: you can redistribute it and/or + modify it under the terms of either: + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your + option) any later version. + + or both in parallel, as here. + + GNU Nettle is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see http://www.gnu.org/licenses/. +*/ + +/* ############################################# + * THIS IS A BACKPORT FROM NETTLE, DO NOT MODIFY + * ############################################# + */ + +#ifndef HAVE_NETTLE_CFB8_ENCRYPT + +#include "cfb8.h" +#include +#include + +/* CFB-8 uses slight optimization: it encrypts or decrypts up to block_size + * bytes and does memcpy/memxor afterwards */ +void +cfb8_encrypt(const void *ctx, nettle_cipher_func *f, + size_t block_size, uint8_t *iv, + size_t length, uint8_t *dst, + const uint8_t *src) +{ + TMP_DECL(buffer, uint8_t, NETTLE_MAX_CIPHER_BLOCK_SIZE * 2); + TMP_DECL(outbuf, uint8_t, NETTLE_MAX_CIPHER_BLOCK_SIZE); + TMP_ALLOC(buffer, block_size * 2); + TMP_ALLOC(outbuf, block_size); + uint8_t pos; + + memcpy(buffer, iv, block_size); + pos = 0; + while (length) + { + uint8_t t; + + if (pos == block_size) + { + memcpy(buffer, buffer + block_size, block_size); + pos = 0; + } + + f(ctx, block_size, outbuf, buffer + pos); + t = *(dst++) = *(src++) ^ outbuf[0]; + buffer[pos + block_size] = t; + length--; + pos ++; + } + memcpy(iv, buffer + pos, block_size); +} + +void +cfb8_decrypt(const void *ctx, nettle_cipher_func *f, + size_t block_size, uint8_t *iv, + size_t length, uint8_t *dst, + const uint8_t *src) +{ + TMP_DECL(buffer, uint8_t, NETTLE_MAX_CIPHER_BLOCK_SIZE * 2); + TMP_DECL(outbuf, uint8_t, NETTLE_MAX_CIPHER_BLOCK_SIZE * 2); + TMP_ALLOC(buffer, block_size * 2); + TMP_ALLOC(outbuf, block_size * 2); + uint8_t i = 0; + + memcpy(buffer, iv, block_size); + memcpy(buffer + block_size, src, + length < block_size ? length : block_size); + + while (length) + { + + for (i = 0; i < length && i < block_size; i++) + f(ctx, block_size, outbuf + i, buffer + i); + + memxor3(dst, src, outbuf, i); + + length -= i; + src += i; + dst += i; + + memcpy(buffer, buffer + block_size, block_size); + memcpy(buffer + block_size, src, + length < block_size ? length : block_size); + + } + + memcpy(iv, buffer + i, block_size); +} +#endif /* HAVE_NETTLE_CFB8_ENCRYPT */ diff --git a/lib/nettle/backport/cfb8.h b/lib/nettle/backport/cfb8.h new file mode 100644 index 0000000000..595c367edc --- /dev/null +++ b/lib/nettle/backport/cfb8.h @@ -0,0 +1,96 @@ +/* backport of cfb.h for CFB8 + + Cipher feedback mode. + + Copyright (C) 2015, 2017 Dmitry Eremin-Solenikov + Copyright (C) 2001 Niels Möller + + This file is part of GNU Nettle. + + GNU Nettle is free software: you can redistribute it and/or + modify it under the terms of either: + + * the GNU Lesser General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your + option) any later version. + + or + + * the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your + option) any later version. + + or both in parallel, as here. + + GNU Nettle is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received copies of the GNU General Public License and + the GNU Lesser General Public License along with this program. If + not, see http://www.gnu.org/licenses/. +*/ + +#ifndef NETTLE_CFB8_H_INCLUDED +#define NETTLE_CFB8_H_INCLUDED + +#include + +#ifndef NETTLE_INTERNAL_H_INCLUDED +#define NETTLE_INTERNAL_H_INCLUDED +#if HAVE_ALLOCA +# define TMP_DECL(name, type, max) type *name +# define TMP_ALLOC(name, size) (name = alloca(sizeof (*name) * (size))) +#else /* !HAVE_ALLOCA */ +# define TMP_DECL(name, type, max) type name[max] +# define TMP_ALLOC(name, size) \ + do { if ((size) > (sizeof(name) / sizeof(name[0]))) abort(); } while (0) +#endif + +#define NETTLE_MAX_CIPHER_BLOCK_SIZE 32 +#endif /* NETTLE_INTERNAL_H_INCLUDED */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Name mangling */ +#define cfb8_encrypt _gnutls_backport_nettle_cfb8_encrypt +#define cfb8_decrypt _gnutls_backport_nettle_cfb8_decrypt + +void +cfb8_encrypt(const void *ctx, nettle_cipher_func *f, + size_t block_size, uint8_t *iv, + size_t length, uint8_t *dst, + const uint8_t *src); + +void +cfb8_decrypt(const void *ctx, nettle_cipher_func *f, + size_t block_size, uint8_t *iv, + size_t length, uint8_t *dst, + const uint8_t *src); + +#define CFB8_CTX CFB_CTX +#define CFB8_SET_IV CFB_SET_IV + +#define CFB8_ENCRYPT(self, f, length, dst, src) \ + (0 ? ((f)(&(self)->ctx, ~(size_t) 0, \ + (uint8_t *) 0, (const uint8_t *) 0)) \ + : cfb8_encrypt((void *) &(self)->ctx, \ + (nettle_cipher_func *) (f), \ + sizeof((self)->iv), (self)->iv, \ + (length), (dst), (src))) + +#define CFB8_DECRYPT(self, f, length, dst, src) \ + (0 ? ((f)(&(self)->ctx, ~(size_t) 0, \ + (uint8_t *) 0, (const uint8_t *) 0)) \ + : cfb8_decrypt((void *) &(self)->ctx, \ + (nettle_cipher_func *) (f), \ + sizeof((self)->iv), (self)->iv, \ + (length), (dst), (src))) + +#ifdef __cplusplus +} +#endif +#endif /* NETTLE_CFB8_H_INCLUDED */ diff --git a/lib/nettle/cipher.c b/lib/nettle/cipher.c index 0f6c737d6f..eab1a03588 100644 --- a/lib/nettle/cipher.c +++ b/lib/nettle/cipher.c @@ -36,14 +36,17 @@ #include #if ENABLE_GOST #include "gost/gost28147.h" -#include #endif #include #include #include #include #include +#ifdef HAVE_NETTLE_CFB8_ENCRYPT #include +#else +#include "cfb8.h" +#endif /* HAVE_NETTLE_CFB8_ENCRYPT */ #include struct nettle_cipher_ctx; -- cgit v1.2.1 From 297aa769c3fc779848f8eb7dbd82ef3690483969 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Wed, 24 Oct 2018 15:45:23 -0400 Subject: Add selftest for CFB8 --- lib/algorithms/ciphers.c | 21 ++++++++++++++++++ lib/crypto-selftests.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ lib/fips.h | 3 +++ 3 files changed, 80 insertions(+) diff --git a/lib/algorithms/ciphers.c b/lib/algorithms/ciphers.c index bbdb1c8524..1a8704be25 100644 --- a/lib/algorithms/ciphers.c +++ b/lib/algorithms/ciphers.c @@ -219,6 +219,27 @@ static const cipher_entry_st algorithms[] = { .type = CIPHER_STREAM, .implicit_iv = 8, .cipher_iv = 8}, + { .name = "AES-128-CFB8", + .id = GNUTLS_CIPHER_AES_128_CFB8, + .blocksize = 16, + .keysize = 16, + .type = CIPHER_BLOCK, + .explicit_iv = 16, + .cipher_iv = 16}, + { .name = "AES-192-CFB8", + .id = GNUTLS_CIPHER_AES_192_CFB8, + .blocksize = 16, + .keysize = 24, + .type = CIPHER_BLOCK, + .explicit_iv = 16, + .cipher_iv = 16}, + { .name = "AES-256-CFB8", + .id = GNUTLS_CIPHER_AES_256_CFB8, + .blocksize = 16, + .keysize = 32, + .type = CIPHER_BLOCK, + .explicit_iv = 16, + .cipher_iv = 16}, { .name = "3DES-CBC", .id = GNUTLS_CIPHER_3DES_CBC, .blocksize = 8, diff --git a/lib/crypto-selftests.c b/lib/crypto-selftests.c index 1e51dfd6c3..19b8210b4e 100644 --- a/lib/crypto-selftests.c +++ b/lib/crypto-selftests.c @@ -373,6 +373,53 @@ const struct cipher_vectors_st arcfour_vectors[] = { /* RFC6229 */ }, }; +const struct cipher_vectors_st aes128_cfb8_vectors[] = { /* NIST 800-38a */ + { + STR(key, key_size, + "\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c"), + STR(plaintext, plaintext_size, + "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a" + "\xae\x2d"), + .ciphertext = (uint8_t *) + "\x3b\x79\x42\x4c\x9c\x0d\xd4\x36\xba\xce\x9e\x0e\xd4\x58\x6a\x4f" + "\x32\xb9", + STR(iv, iv_size, + "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"), + }, +}; + +const struct cipher_vectors_st aes192_cfb8_vectors[] = { /* NIST 800-38a */ + { + STR(key, key_size, + "\x8e\x73\xb0\xf7\xda\x0e\x64\x52\xc8\x10\xf3\x2b\x80\x90\x79\xe5" + "\x62\xf8\xea\xd2\x52\x2c\x6b\x7b"), + STR(plaintext, plaintext_size, + "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a" + "\xae\x2d"), + .ciphertext = (uint8_t *) + "\xcd\xa2\x52\x1e\xf0\xa9\x05\xca\x44\xcd\x05\x7c\xbf\x0d\x47\xa0" + "\x67\x8a", + STR(iv, iv_size, + "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"), + }, +}; + +const struct cipher_vectors_st aes256_cfb8_vectors[] = { /* NIST 800-38a */ + { + STR(key, key_size, + "\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"), + STR(plaintext, plaintext_size, + "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a" + "\xae\x2d"), + .ciphertext = (uint8_t *) + "\xdc\x1f\x1a\x85\x20\xa6\x4d\xb5\x5f\xcc\x8a\xc5\x54\x84\x4e\x88" + "\x97\x00", + STR(iv, iv_size, + "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"), + }, +}; + static int test_cipher(gnutls_cipher_algorithm_t cipher, const struct cipher_vectors_st *vectors, size_t vectors_size, unsigned flags) @@ -1339,6 +1386,15 @@ int gnutls_cipher_self_test(unsigned flags, gnutls_cipher_algorithm_t cipher) FALLTHROUGH; 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); + FALLTHROUGH; + CASE(GNUTLS_CIPHER_AES_192_CFB8, test_cipher, + aes192_cfb8_vectors); + FALLTHROUGH; + CASE(GNUTLS_CIPHER_AES_256_CFB8, test_cipher, + aes256_cfb8_vectors); break; default: return gnutls_assert_val(GNUTLS_E_NO_SELF_TEST); diff --git a/lib/fips.h b/lib/fips.h index 7d3f3cfd39..4e09916ac4 100644 --- a/lib/fips.h +++ b/lib/fips.h @@ -139,6 +139,9 @@ static unsigned is_cipher_algo_forbidden(gnutls_cipher_algorithm_t algo) case GNUTLS_CIPHER_3DES_CBC: case GNUTLS_CIPHER_AES_128_CCM_8: case GNUTLS_CIPHER_AES_256_CCM_8: + case GNUTLS_CIPHER_AES_128_CFB8: + case GNUTLS_CIPHER_AES_192_CFB8: + case GNUTLS_CIPHER_AES_256_CFB8: return 0; default: if (mode == GNUTLS_FIPS140_LAX) -- cgit v1.2.1