From b73facdeca098be7e538e556c1a293942db3110c Mon Sep 17 00:00:00 2001 From: jsing <> Date: Mon, 21 Jul 2025 10:24:23 +0000 Subject: Move AES-NI from EVP to AES for CCM mode. The mode implementation for CCM has two variants - one takes the block function, while the other takes a "ccm64" function. The latter is expected to handle the lower 64 bits of the IV/counter but only for 16 byte blocks. The AES-NI implementation for CCM currently uses the second variant. Provide aes_ccm64_encrypt_internal() as a function that can be replaced on a machine dependent basis, along with an aes_ccm64_encrypt_generic() function that provides the default implementation and can be used as a fallback. Wire up the AES-NI version for amd64 and i386, change EVP's aes_ccm_cipher() to use CRYPTO_ctr128_{en,de}crypt_ccm64() with aes_ccm64_encrypt_internal()) and remove the various AES-NI specific EVP_CIPHER methods for CCM. ok tb@ --- src/lib/libcrypto/aes/aes.c | 70 +++++++++++++++++- src/lib/libcrypto/aes/aes_amd64.c | 30 +++++++- src/lib/libcrypto/aes/aes_i386.c | 30 +++++++- src/lib/libcrypto/aes/aes_local.h | 10 ++- src/lib/libcrypto/arch/amd64/crypto_arch.h | 3 +- src/lib/libcrypto/arch/i386/crypto_arch.h | 3 +- src/lib/libcrypto/evp/e_aes.c | 111 ++--------------------------- 7 files changed, 145 insertions(+), 112 deletions(-) (limited to 'src') diff --git a/src/lib/libcrypto/aes/aes.c b/src/lib/libcrypto/aes/aes.c index cbfb548b3b..33e6273268 100644 --- a/src/lib/libcrypto/aes/aes.c +++ b/src/lib/libcrypto/aes/aes.c @@ -1,4 +1,4 @@ -/* $OpenBSD: aes.c,v 1.12 2025/07/20 08:55:49 jsing Exp $ */ +/* $OpenBSD: aes.c,v 1.13 2025/07/21 10:24:23 jsing Exp $ */ /* ==================================================================== * Copyright (c) 2002-2006 The OpenSSL Project. All rights reserved. * @@ -172,6 +172,74 @@ AES_cfb8_encrypt(const unsigned char *in, unsigned char *out, size_t length, } LCRYPTO_ALIAS(AES_cfb8_encrypt); +void +aes_ccm64_encrypt_generic(const unsigned char *in, unsigned char *out, + size_t blocks, const void *key, const unsigned char ivec[16], + unsigned char cmac[16], int encrypt) +{ + uint8_t iv[AES_BLOCK_SIZE], buf[AES_BLOCK_SIZE]; + uint8_t in_mask; + uint64_t ctr; + int i; + + in_mask = 0 - (encrypt != 0); + + memcpy(iv, ivec, sizeof(iv)); + + ctr = crypto_load_be64toh(&iv[8]); + + while (blocks > 0) { + crypto_store_htobe64(&iv[8], ctr); + aes_encrypt_internal(iv, buf, key); + ctr++; + + for (i = 0; i < 16; i++) { + out[i] = in[i] ^ buf[i]; + cmac[i] ^= (in[i] & in_mask) | (out[i] & ~in_mask); + } + + aes_encrypt_internal(cmac, cmac, key); + + in += 16; + out += 16; + blocks--; + } + + explicit_bzero(buf, sizeof(buf)); + explicit_bzero(iv, sizeof(iv)); +} + +#ifdef HAVE_AES_CCM64_ENCRYPT_INTERNAL +void aes_ccm64_encrypt_internal(const unsigned char *in, unsigned char *out, + size_t blocks, const void *key, const unsigned char ivec[16], + unsigned char cmac[16], int encrypt); + +#else +static inline void +aes_ccm64_encrypt_internal(const unsigned char *in, unsigned char *out, + size_t blocks, const void *key, const unsigned char ivec[16], + unsigned char cmac[16], int encrypt) +{ + aes_ccm64_encrypt_generic(in, out, blocks, key, ivec, cmac, encrypt); +} +#endif + +void +aes_ccm64_encrypt_ccm128f(const unsigned char *in, unsigned char *out, + size_t blocks, const void *key, const unsigned char ivec[16], + unsigned char cmac[16]) +{ + aes_ccm64_encrypt_internal(in, out, blocks, key, ivec, cmac, 1); +} + +void +aes_ccm64_decrypt_ccm128f(const unsigned char *in, unsigned char *out, + size_t blocks, const void *key, const unsigned char ivec[16], + unsigned char cmac[16]) +{ + aes_ccm64_encrypt_internal(in, out, blocks, key, ivec, cmac, 0); +} + void aes_ctr32_encrypt_generic(const unsigned char *in, unsigned char *out, size_t blocks, const AES_KEY *key, const unsigned char ivec[AES_BLOCK_SIZE]) diff --git a/src/lib/libcrypto/aes/aes_amd64.c b/src/lib/libcrypto/aes/aes_amd64.c index 5a40274675..436983d872 100644 --- a/src/lib/libcrypto/aes/aes_amd64.c +++ b/src/lib/libcrypto/aes/aes_amd64.c @@ -1,4 +1,4 @@ -/* $OpenBSD: aes_amd64.c,v 1.3 2025/07/13 06:01:33 jsing Exp $ */ +/* $OpenBSD: aes_amd64.c,v 1.4 2025/07/21 10:24:23 jsing Exp $ */ /* * Copyright (c) 2025 Joel Sing * @@ -33,6 +33,10 @@ void aes_decrypt_generic(const unsigned char *in, unsigned char *out, void aes_cbc_encrypt_generic(const unsigned char *in, unsigned char *out, size_t len, const AES_KEY *key, unsigned char *ivec, const int enc); +void aes_ccm64_encrypt_generic(const unsigned char *in, unsigned char *out, + size_t blocks, const void *key, const unsigned char ivec[16], + unsigned char cmac[16], int encrypt); + void aes_ctr32_encrypt_generic(const unsigned char *in, unsigned char *out, size_t blocks, const AES_KEY *key, const unsigned char ivec[AES_BLOCK_SIZE]); @@ -53,6 +57,14 @@ void aesni_decrypt(const unsigned char *in, unsigned char *out, void aesni_cbc_encrypt(const unsigned char *in, unsigned char *out, size_t len, const AES_KEY *key, unsigned char *ivec, const int enc); +void aesni_ccm64_encrypt_blocks(const unsigned char *in, unsigned char *out, + size_t blocks, const void *key, const unsigned char ivec[16], + unsigned char cmac[16]); + +void aesni_ccm64_decrypt_blocks(const unsigned char *in, unsigned char *out, + size_t blocks, const void *key, const unsigned char ivec[16], + unsigned char cmac[16]); + void aesni_ctr32_encrypt_blocks(const unsigned char *in, unsigned char *out, size_t blocks, const void *key, const unsigned char *ivec); @@ -120,6 +132,22 @@ aes_cbc_encrypt_internal(const unsigned char *in, unsigned char *out, aes_cbc_encrypt_generic(in, out, len, key, ivec, enc); } +void +aes_ccm64_encrypt_internal(const unsigned char *in, unsigned char *out, + size_t blocks, const void *key, const unsigned char ivec[16], + unsigned char cmac[16], int encrypt) +{ + if ((crypto_cpu_caps_amd64 & CRYPTO_CPU_CAPS_AMD64_AES) != 0) { + if (encrypt) + aesni_ccm64_encrypt_blocks(in, out, blocks, key, ivec, cmac); + else + aesni_ccm64_decrypt_blocks(in, out, blocks, key, ivec, cmac); + return; + } + + aes_ccm64_encrypt_generic(in, out, blocks, key, ivec, cmac, encrypt); +} + void aes_ctr32_encrypt_internal(const unsigned char *in, unsigned char *out, size_t blocks, const AES_KEY *key, const unsigned char ivec[AES_BLOCK_SIZE]) diff --git a/src/lib/libcrypto/aes/aes_i386.c b/src/lib/libcrypto/aes/aes_i386.c index 73b75d28f5..7f2241eaf5 100644 --- a/src/lib/libcrypto/aes/aes_i386.c +++ b/src/lib/libcrypto/aes/aes_i386.c @@ -1,4 +1,4 @@ -/* $OpenBSD: aes_i386.c,v 1.3 2025/07/13 06:01:33 jsing Exp $ */ +/* $OpenBSD: aes_i386.c,v 1.4 2025/07/21 10:24:23 jsing Exp $ */ /* * Copyright (c) 2025 Joel Sing * @@ -33,6 +33,10 @@ void aes_decrypt_generic(const unsigned char *in, unsigned char *out, void aes_cbc_encrypt_generic(const unsigned char *in, unsigned char *out, size_t len, const AES_KEY *key, unsigned char *ivec, const int enc); +void aes_ccm64_encrypt_generic(const unsigned char *in, unsigned char *out, + size_t blocks, const void *key, const unsigned char ivec[16], + unsigned char cmac[16], int encrypt); + void aes_ctr32_encrypt_generic(const unsigned char *in, unsigned char *out, size_t blocks, const AES_KEY *key, const unsigned char ivec[AES_BLOCK_SIZE]); @@ -53,6 +57,14 @@ void aesni_decrypt(const unsigned char *in, unsigned char *out, void aesni_cbc_encrypt(const unsigned char *in, unsigned char *out, size_t len, const AES_KEY *key, unsigned char *ivec, const int enc); +void aesni_ccm64_encrypt_blocks(const unsigned char *in, unsigned char *out, + size_t blocks, const void *key, const unsigned char ivec[16], + unsigned char cmac[16]); + +void aesni_ccm64_decrypt_blocks(const unsigned char *in, unsigned char *out, + size_t blocks, const void *key, const unsigned char ivec[16], + unsigned char cmac[16]); + void aesni_ctr32_encrypt_blocks(const unsigned char *in, unsigned char *out, size_t blocks, const void *key, const unsigned char *ivec); @@ -120,6 +132,22 @@ aes_cbc_encrypt_internal(const unsigned char *in, unsigned char *out, aes_cbc_encrypt_generic(in, out, len, key, ivec, enc); } +void +aes_ccm64_encrypt_internal(const unsigned char *in, unsigned char *out, + size_t blocks, const void *key, const unsigned char ivec[16], + unsigned char cmac[16], int encrypt) +{ + if ((crypto_cpu_caps_i386 & CRYPTO_CPU_CAPS_I386_AES) != 0) { + if (encrypt) + aesni_ccm64_encrypt_blocks(in, out, blocks, key, ivec, cmac); + else + aesni_ccm64_decrypt_blocks(in, out, blocks, key, ivec, cmac); + return; + } + + aes_ccm64_encrypt_generic(in, out, blocks, key, ivec, cmac, encrypt); +} + void aes_ctr32_encrypt_internal(const unsigned char *in, unsigned char *out, size_t blocks, const AES_KEY *key, const unsigned char ivec[AES_BLOCK_SIZE]) diff --git a/src/lib/libcrypto/aes/aes_local.h b/src/lib/libcrypto/aes/aes_local.h index f68d4624e7..539373ea06 100644 --- a/src/lib/libcrypto/aes/aes_local.h +++ b/src/lib/libcrypto/aes/aes_local.h @@ -1,4 +1,4 @@ -/* $OpenBSD: aes_local.h,v 1.9 2025/07/13 06:01:33 jsing Exp $ */ +/* $OpenBSD: aes_local.h,v 1.10 2025/07/21 10:24:23 jsing Exp $ */ /* ==================================================================== * Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved. * @@ -66,6 +66,14 @@ __BEGIN_HIDDEN_DECLS void aes_ctr32_encrypt_ctr128f(const unsigned char *in, unsigned char *out, size_t blocks, const void *key, const unsigned char ivec[AES_BLOCK_SIZE]); +void aes_ccm64_encrypt_ccm128f(const unsigned char *in, unsigned char *out, + size_t blocks, const void *key, const unsigned char ivec[16], + unsigned char cmac[16]); + +void aes_ccm64_decrypt_ccm128f(const unsigned char *in, unsigned char *out, + size_t blocks, const void *key, const unsigned char ivec[16], + unsigned char cmac[16]); + void aes_ecb_encrypt_internal(const unsigned char *in, unsigned char *out, size_t len, const AES_KEY *key, int encrypt); diff --git a/src/lib/libcrypto/arch/amd64/crypto_arch.h b/src/lib/libcrypto/arch/amd64/crypto_arch.h index 7c3c89a088..a51021a307 100644 --- a/src/lib/libcrypto/arch/amd64/crypto_arch.h +++ b/src/lib/libcrypto/arch/amd64/crypto_arch.h @@ -1,4 +1,4 @@ -/* $OpenBSD: crypto_arch.h,v 1.10 2025/07/13 06:01:33 jsing Exp $ */ +/* $OpenBSD: crypto_arch.h,v 1.11 2025/07/21 10:24:23 jsing Exp $ */ /* * Copyright (c) 2024 Joel Sing * @@ -38,6 +38,7 @@ extern uint64_t crypto_cpu_caps_amd64; #define HAVE_AES_ENCRYPT_INTERNAL #define HAVE_AES_DECRYPT_INTERNAL #define HAVE_AES_CBC_ENCRYPT_INTERNAL +#define HAVE_AES_CCM64_ENCRYPT_INTERNAL #define HAVE_AES_CTR32_ENCRYPT_INTERNAL #define HAVE_AES_XTS_ENCRYPT_INTERNAL diff --git a/src/lib/libcrypto/arch/i386/crypto_arch.h b/src/lib/libcrypto/arch/i386/crypto_arch.h index 8b292165fb..34d041b382 100644 --- a/src/lib/libcrypto/arch/i386/crypto_arch.h +++ b/src/lib/libcrypto/arch/i386/crypto_arch.h @@ -1,4 +1,4 @@ -/* $OpenBSD: crypto_arch.h,v 1.9 2025/07/13 06:01:33 jsing Exp $ */ +/* $OpenBSD: crypto_arch.h,v 1.10 2025/07/21 10:24:23 jsing Exp $ */ /* * Copyright (c) 2024 Joel Sing * @@ -38,6 +38,7 @@ extern uint64_t crypto_cpu_caps_i386; #define HAVE_AES_ENCRYPT_INTERNAL #define HAVE_AES_DECRYPT_INTERNAL #define HAVE_AES_CBC_ENCRYPT_INTERNAL +#define HAVE_AES_CCM64_ENCRYPT_INTERNAL #define HAVE_AES_CTR32_ENCRYPT_INTERNAL #define HAVE_AES_XTS_ENCRYPT_INTERNAL diff --git a/src/lib/libcrypto/evp/e_aes.c b/src/lib/libcrypto/evp/e_aes.c index 851da9ded6..0949c8bdb4 100644 --- a/src/lib/libcrypto/evp/e_aes.c +++ b/src/lib/libcrypto/evp/e_aes.c @@ -1,4 +1,4 @@ -/* $OpenBSD: e_aes.c,v 1.79 2025/07/13 06:01:33 jsing Exp $ */ +/* $OpenBSD: e_aes.c,v 1.80 2025/07/21 10:24:23 jsing Exp $ */ /* ==================================================================== * Copyright (c) 2001-2011 The OpenSSL Project. All rights reserved. * @@ -95,7 +95,6 @@ typedef struct { int len_set; /* Set if message length set */ int L, M; /* L and M parameters from RFC3610 */ CCM128_CONTEXT ccm; - ccm128_f str; } EVP_AES_CCM_CTX; #define MAXBITCHUNK ((size_t)1<<(sizeof(size_t)*8-4)) @@ -114,27 +113,9 @@ typedef struct { */ #define AESNI_CAPABLE (crypto_cpu_caps_ia32() & CPUCAP_MASK_AESNI) -int aesni_set_encrypt_key(const unsigned char *userKey, int bits, - AES_KEY *key); -int aesni_set_decrypt_key(const unsigned char *userKey, int bits, - AES_KEY *key); - -void aesni_encrypt(const unsigned char *in, unsigned char *out, - const AES_KEY *key); -void aesni_decrypt(const unsigned char *in, unsigned char *out, - const AES_KEY *key); - void aesni_ecb_encrypt(const unsigned char *in, unsigned char *out, size_t length, const AES_KEY *key, int enc); -void aesni_ccm64_encrypt_blocks (const unsigned char *in, unsigned char *out, - size_t blocks, const void *key, const unsigned char ivec[16], - unsigned char cmac[16]); - -void aesni_ccm64_decrypt_blocks (const unsigned char *in, unsigned char *out, - size_t blocks, const void *key, const unsigned char ivec[16], - unsigned char cmac[16]); - static int aesni_ecb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, size_t len) @@ -146,29 +127,6 @@ aesni_ecb_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, return 1; } - -static int -aesni_ccm_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, - const unsigned char *iv, int enc) -{ - EVP_AES_CCM_CTX *cctx = ctx->cipher_data; - - if (!iv && !key) - return 1; - if (key) { - aesni_set_encrypt_key(key, ctx->key_len * 8, &cctx->ks); - CRYPTO_ccm128_init(&cctx->ccm, cctx->M, cctx->L, - &cctx->ks, (block128_f)aesni_encrypt); - cctx->str = enc ? (ccm128_f)aesni_ccm64_encrypt_blocks : - (ccm128_f)aesni_ccm64_decrypt_blocks; - cctx->key_set = 1; - } - if (iv) { - memcpy(ctx->iv, iv, 15 - cctx->L); - cctx->iv_set = 1; - } - return 1; -} #endif static int @@ -1353,7 +1311,6 @@ aes_ccm_init_key(EVP_CIPHER_CTX *ctx, const unsigned char *key, AES_set_encrypt_key(key, ctx->key_len * 8, &cctx->ks); CRYPTO_ccm128_init(&cctx->ccm, cctx->M, cctx->L, &cctx->ks, (block128_f)AES_encrypt); - cctx->str = NULL; cctx->key_set = 1; } if (iv) { @@ -1405,15 +1362,15 @@ aes_ccm_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, cctx->len_set = 1; } if (ctx->encrypt) { - if (cctx->str ? CRYPTO_ccm128_encrypt_ccm64(ccm, in, out, len, - cctx->str) : CRYPTO_ccm128_encrypt(ccm, in, out, len)) + if (CRYPTO_ccm128_encrypt_ccm64(ccm, in, out, len, + aes_ccm64_encrypt_ccm128f) != 0) return -1; cctx->tag_set = 1; return len; } else { int rv = -1; - if (cctx->str ? !CRYPTO_ccm128_decrypt_ccm64(ccm, in, out, len, - cctx->str) : !CRYPTO_ccm128_decrypt(ccm, in, out, len)) { + if (CRYPTO_ccm128_decrypt_ccm64(ccm, in, out, len, + aes_ccm64_decrypt_ccm128f) == 0) { unsigned char tag[16]; if (CRYPTO_ccm128_tag(ccm, tag, cctx->M)) { if (timingsafe_memcmp(tag, ctx->buf, cctx->M) == 0) @@ -1427,24 +1384,8 @@ aes_ccm_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, cctx->len_set = 0; return rv; } - } -#ifdef AESNI_CAPABLE -static const EVP_CIPHER aesni_128_ccm = { - .nid = NID_aes_128_ccm, - .block_size = 1, - .key_len = 16, - .iv_len = 12, - .flags = CUSTOM_FLAGS | EVP_CIPH_CCM_MODE, - .init = aesni_ccm_init_key, - .do_cipher = aes_ccm_cipher, - .cleanup = NULL, - .ctx_size = sizeof(EVP_AES_CCM_CTX), - .ctrl = aes_ccm_ctrl, -}; -#endif - static const EVP_CIPHER aes_128_ccm = { .nid = NID_aes_128_ccm, .block_size = 1, @@ -1461,29 +1402,10 @@ static const EVP_CIPHER aes_128_ccm = { const EVP_CIPHER * EVP_aes_128_ccm(void) { -#ifdef AESNI_CAPABLE - return AESNI_CAPABLE ? &aesni_128_ccm : &aes_128_ccm; -#else return &aes_128_ccm; -#endif } LCRYPTO_ALIAS(EVP_aes_128_ccm); -#ifdef AESNI_CAPABLE -static const EVP_CIPHER aesni_192_ccm = { - .nid = NID_aes_192_ccm, - .block_size = 1, - .key_len = 24, - .iv_len = 12, - .flags = CUSTOM_FLAGS | EVP_CIPH_CCM_MODE, - .init = aesni_ccm_init_key, - .do_cipher = aes_ccm_cipher, - .cleanup = NULL, - .ctx_size = sizeof(EVP_AES_CCM_CTX), - .ctrl = aes_ccm_ctrl, -}; -#endif - static const EVP_CIPHER aes_192_ccm = { .nid = NID_aes_192_ccm, .block_size = 1, @@ -1500,29 +1422,10 @@ static const EVP_CIPHER aes_192_ccm = { const EVP_CIPHER * EVP_aes_192_ccm(void) { -#ifdef AESNI_CAPABLE - return AESNI_CAPABLE ? &aesni_192_ccm : &aes_192_ccm; -#else return &aes_192_ccm; -#endif } LCRYPTO_ALIAS(EVP_aes_192_ccm); -#ifdef AESNI_CAPABLE -static const EVP_CIPHER aesni_256_ccm = { - .nid = NID_aes_256_ccm, - .block_size = 1, - .key_len = 32, - .iv_len = 12, - .flags = CUSTOM_FLAGS | EVP_CIPH_CCM_MODE, - .init = aesni_ccm_init_key, - .do_cipher = aes_ccm_cipher, - .cleanup = NULL, - .ctx_size = sizeof(EVP_AES_CCM_CTX), - .ctrl = aes_ccm_ctrl, -}; -#endif - static const EVP_CIPHER aes_256_ccm = { .nid = NID_aes_256_ccm, .block_size = 1, @@ -1539,11 +1442,7 @@ static const EVP_CIPHER aes_256_ccm = { const EVP_CIPHER * EVP_aes_256_ccm(void) { -#ifdef AESNI_CAPABLE - return AESNI_CAPABLE ? &aesni_256_ccm : &aes_256_ccm; -#else return &aes_256_ccm; -#endif } LCRYPTO_ALIAS(EVP_aes_256_ccm); -- cgit v1.2.3-55-g6feb