From f16cd4278fad69a569006de1136997b83db51898 Mon Sep 17 00:00:00 2001 From: Steven Valdez Date: Tue, 13 Feb 2018 13:39:42 -0500 Subject: [PATCH] Add AES_128_CCM AEAD. Change-Id: I830be64209deada0f24c3b6d50dc86155085c377 Reviewed-on: https://boringssl-review.googlesource.com/25904 Commit-Queue: Steven Valdez Reviewed-by: Steven Valdez CQ-Verified: CQ bot account: commit-bot@chromium.org --- crypto/cipher_extra/CMakeLists.txt | 1 + crypto/cipher_extra/aead_test.cc | 38 +++ crypto/cipher_extra/e_aesccm.c | 171 ++++++++++++ .../test/aes_128_ccm_bluetooth_tests.txt | 20 ++ crypto/fipsmodule/bcm.c | 1 + crypto/fipsmodule/modes/ccm.c | 258 ++++++++++++++++++ crypto/fipsmodule/modes/internal.h | 36 +++ include/openssl/aead.h | 4 + sources.cmake | 1 + tool/speed.cc | 2 + 10 files changed, 532 insertions(+) create mode 100644 crypto/cipher_extra/e_aesccm.c create mode 100644 crypto/cipher_extra/test/aes_128_ccm_bluetooth_tests.txt create mode 100644 crypto/fipsmodule/modes/ccm.c diff --git a/crypto/cipher_extra/CMakeLists.txt b/crypto/cipher_extra/CMakeLists.txt index 8af36301..d2a15aed 100644 --- a/crypto/cipher_extra/CMakeLists.txt +++ b/crypto/cipher_extra/CMakeLists.txt @@ -22,6 +22,7 @@ add_library( e_rc4.c e_aesgcmsiv.c e_aesctrhmac.c + e_aesccm.c e_chacha20poly1305.c tls_cbc.c diff --git a/crypto/cipher_extra/aead_test.cc b/crypto/cipher_extra/aead_test.cc index a40d673c..dbd8428f 100644 --- a/crypto/cipher_extra/aead_test.cc +++ b/crypto/cipher_extra/aead_test.cc @@ -93,6 +93,8 @@ static const struct KnownAEAD kAEADs[] = { "aes_128_ctr_hmac_sha256.txt", false, true, 0}, {"AES_256_CTR_HMAC_SHA256", EVP_aead_aes_256_ctr_hmac_sha256, "aes_256_ctr_hmac_sha256.txt", false, true, 0}, + {"AES_128_CCM_BLUETOOTH", EVP_aead_aes_128_ccm_bluetooth, + "aes_128_ccm_bluetooth_tests.txt", false, false, 0}, }; class PerAEADTest : public testing::TestWithParam { @@ -651,3 +653,39 @@ TEST(AEADTest, AESGCMEmptyNonce) { EXPECT_EQ(ERR_LIB_CIPHER, ERR_GET_LIB(err)); EXPECT_EQ(CIPHER_R_INVALID_NONCE_SIZE, ERR_GET_REASON(err)); } + +TEST(AEADTest, AESCCMLargeAD) { + static const std::vector kKey(16, 'A'); + static const std::vector kNonce(13, 'N'); + static const std::vector kAD(65536, 'D'); + static const std::vector kPlaintext = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}; + static const std::vector kCiphertext = { + 0xa2, 0x12, 0x3f, 0x0b, 0x07, 0xd5, 0x02, 0xff, + 0xa9, 0xcd, 0xa0, 0xf3, 0x69, 0x1c, 0x49, 0x0c}; + static const std::vector kTag = {0x4a, 0x31, 0x82, 0x96}; + + // Test AES-128-CCM-Bluetooth. + bssl::ScopedEVP_AEAD_CTX ctx; + ASSERT_TRUE(EVP_AEAD_CTX_init(ctx.get(), EVP_aead_aes_128_ccm_bluetooth(), + kKey.data(), kKey.size(), + EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr)); + + std::vector out(kCiphertext.size() + kTag.size()); + size_t out_len; + EXPECT_TRUE(EVP_AEAD_CTX_seal(ctx.get(), out.data(), &out_len, out.size(), + kNonce.data(), kNonce.size(), kPlaintext.data(), + kPlaintext.size(), kAD.data(), kAD.size())); + + ASSERT_EQ(out_len, kCiphertext.size() + kTag.size()); + EXPECT_EQ(Bytes(kCiphertext), Bytes(out.data(), kCiphertext.size())); + EXPECT_EQ(Bytes(kTag), Bytes(out.data() + kCiphertext.size(), kTag.size())); + + EXPECT_TRUE(EVP_AEAD_CTX_open(ctx.get(), out.data(), &out_len, out.size(), + kNonce.data(), kNonce.size(), out.data(), + out.size(), kAD.data(), kAD.size())); + + ASSERT_EQ(out_len, kPlaintext.size()); + EXPECT_EQ(Bytes(kPlaintext), Bytes(out.data(), kPlaintext.size())); +} diff --git a/crypto/cipher_extra/e_aesccm.c b/crypto/cipher_extra/e_aesccm.c new file mode 100644 index 00000000..93678e00 --- /dev/null +++ b/crypto/cipher_extra/e_aesccm.c @@ -0,0 +1,171 @@ +/* Copyright (c) 2018, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + +#include + +#include +#include +#include + +#include "../fipsmodule/cipher/internal.h" + + +#define EVP_AEAD_AES_CCM_BLUETOOTH_TAG_LEN 4 +#define EVP_AEAD_AES_CCM_BLUETOOTH_NONCE_LEN 13 + +#define EVP_AEAD_AES_CCM_MAX_TAG_LEN 16 + +struct aead_aes_ccm_ctx { + union { + double align; + AES_KEY ks; + } ks; + CCM128_CONTEXT ccm; +}; + +static int aead_aes_ccm_bluetooth_init(EVP_AEAD_CTX *ctx, const uint8_t *key, + size_t key_len, size_t tag_len) { + if (key_len != 16) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_KEY_LENGTH); + return 0; // EVP_AEAD_CTX_init should catch this. + } + + if (tag_len == EVP_AEAD_DEFAULT_TAG_LENGTH) { + tag_len = EVP_AEAD_AES_CCM_BLUETOOTH_TAG_LEN; + } + + if (tag_len != EVP_AEAD_AES_CCM_BLUETOOTH_TAG_LEN) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TAG_TOO_LARGE); + return 0; + } + + struct aead_aes_ccm_ctx *ccm_ctx = + OPENSSL_malloc(sizeof(struct aead_aes_ccm_ctx)); + if (ccm_ctx == NULL) { + OPENSSL_PUT_ERROR(CIPHER, ERR_R_MALLOC_FAILURE); + return 0; + } + + block128_f block; + ctr128_f ctr = aes_ctr_set_key(&ccm_ctx->ks.ks, NULL, &block, key, key_len); + ctx->tag_len = tag_len; + if (!CRYPTO_ccm128_init(&ccm_ctx->ccm, &ccm_ctx->ks.ks, block, ctr, tag_len, + 15 - EVP_AEAD_AES_CCM_BLUETOOTH_NONCE_LEN)) { + OPENSSL_PUT_ERROR(CIPHER, ERR_R_INTERNAL_ERROR); + OPENSSL_free(ccm_ctx); + return 0; + } + + ctx->aead_state = ccm_ctx; + return 1; +} + +static void aead_aes_ccm_cleanup(EVP_AEAD_CTX *ctx) { + OPENSSL_free(ctx->aead_state); +} + +static int aead_aes_ccm_seal_scatter( + const EVP_AEAD_CTX *ctx, uint8_t *out, uint8_t *out_tag, + size_t *out_tag_len, size_t max_out_tag_len, const uint8_t *nonce, + size_t nonce_len, const uint8_t *in, size_t in_len, const uint8_t *extra_in, + size_t extra_in_len, const uint8_t *ad, size_t ad_len) { + const struct aead_aes_ccm_ctx *ccm_ctx = ctx->aead_state; + + if (in_len > CRYPTO_ccm128_max_input(&ccm_ctx->ccm)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + if (max_out_tag_len < ctx->tag_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); + return 0; + } + + if (nonce_len != EVP_AEAD_nonce_length(ctx->aead)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_NONCE_SIZE); + return 0; + } + + if (!CRYPTO_ccm128_encrypt(&ccm_ctx->ccm, &ccm_ctx->ks.ks, out, out_tag, + ctx->tag_len, nonce, nonce_len, in, in_len, ad, + ad_len)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + *out_tag_len = ctx->tag_len; + return 1; +} + +static int aead_aes_ccm_open_gather(const EVP_AEAD_CTX *ctx, uint8_t *out, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, + const uint8_t *in_tag, size_t in_tag_len, + const uint8_t *ad, size_t ad_len) { + const struct aead_aes_ccm_ctx *ccm_ctx = ctx->aead_state; + + if (in_len > CRYPTO_ccm128_max_input(&ccm_ctx->ccm)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + if (nonce_len != EVP_AEAD_nonce_length(ctx->aead)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_NONCE_SIZE); + return 0; + } + + if (in_tag_len != ctx->tag_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + + uint8_t tag[EVP_AEAD_AES_CCM_MAX_TAG_LEN]; + assert(ctx->tag_len <= EVP_AEAD_AES_CCM_MAX_TAG_LEN); + if (!CRYPTO_ccm128_decrypt(&ccm_ctx->ccm, &ccm_ctx->ks.ks, out, tag, + ctx->tag_len, nonce, nonce_len, in, in_len, ad, + ad_len)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + if (CRYPTO_memcmp(tag, in_tag, ctx->tag_len) != 0) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + + return 1; +} + +static const EVP_AEAD aead_aes_128_ccm_bluetooth = { + 16, + EVP_AEAD_AES_CCM_BLUETOOTH_NONCE_LEN, // nonce length + EVP_AEAD_AES_CCM_BLUETOOTH_TAG_LEN, // overhead + EVP_AEAD_AES_CCM_BLUETOOTH_TAG_LEN, // max tag length + 0, // seal_scatter_supports_extra_in + + aead_aes_ccm_bluetooth_init, + NULL /* init_with_direction */, + aead_aes_ccm_cleanup, + NULL /* open */, + aead_aes_ccm_seal_scatter, + aead_aes_ccm_open_gather, + NULL /* get_iv */, + NULL /* tag_len */, +}; + +const EVP_AEAD *EVP_aead_aes_128_ccm_bluetooth(void) { + return &aead_aes_128_ccm_bluetooth; +} diff --git a/crypto/cipher_extra/test/aes_128_ccm_bluetooth_tests.txt b/crypto/cipher_extra/test/aes_128_ccm_bluetooth_tests.txt new file mode 100644 index 00000000..98c134de --- /dev/null +++ b/crypto/cipher_extra/test/aes_128_ccm_bluetooth_tests.txt @@ -0,0 +1,20 @@ +KEY: 404142434445464748494a4b4c4d4e4f +NONCE: 101112131415161718191a1b1c +IN: 20212223 +AD: 0001020304050607 +CT: 69915dad +TAG: 064617ca + +KEY: 404142434445464748494a4b4c4d4e4f +NONCE: 101112131415161718191a1b1c +IN: 202122232425262728292a2b2c2d2e2f +AD: 0001020304050607 +CT: 69915dad1e84c6376a68c2967e4dab61 +TAG: 99763ebb + +KEY: 404142434445464748494a4b4c4d4e4f +NONCE: 101112131415161718191a1b1c +IN: 202122232425262728292a2b2c2d2e2f +AD: +CT: 69915dad1e84c6376a68c2967e4dab61 +TAG: c4630026 diff --git a/crypto/fipsmodule/bcm.c b/crypto/fipsmodule/bcm.c index e066fa70..028ec4e9 100644 --- a/crypto/fipsmodule/bcm.c +++ b/crypto/fipsmodule/bcm.c @@ -70,6 +70,7 @@ #include "md4/md4.c" #include "md5/md5.c" #include "modes/cbc.c" +#include "modes/ccm.c" #include "modes/cfb.c" #include "modes/ctr.c" #include "modes/gcm.c" diff --git a/crypto/fipsmodule/modes/ccm.c b/crypto/fipsmodule/modes/ccm.c new file mode 100644 index 00000000..dba9262c --- /dev/null +++ b/crypto/fipsmodule/modes/ccm.c @@ -0,0 +1,258 @@ +/* ==================================================================== + * Copyright (c) 2011 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + */ + +#include +#include + +#include +#include + +#include "../../internal.h" +#include "internal.h" + + +struct ccm128_state { + union { + uint64_t u[2]; + uint8_t c[16]; + } nonce, cmac; +}; + +int CRYPTO_ccm128_init(CCM128_CONTEXT *ctx, const void *key, block128_f block, + ctr128_f ctr, unsigned M, unsigned L) { + if (M < 4 || M > 16 || (M & 1) != 0 || L < 2 || L > 8) { + return 0; + } + ctx->block = block; + ctx->ctr = ctr; + ctx->M = M; + ctx->L = L; + return 1; +} + +size_t CRYPTO_ccm128_max_input(const CCM128_CONTEXT *ctx) { + return ctx->L >= sizeof(size_t) ? (size_t)-1 + : (((size_t)1) << (ctx->L * 8)) - 1; +} + +static int ccm128_init_state(const CCM128_CONTEXT *ctx, + struct ccm128_state *state, const void *key, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *aad, size_t aad_len, + size_t plaintext_len) { + const block128_f block = ctx->block; + const unsigned M = ctx->M; + const unsigned L = ctx->L; + + // |L| determines the expected |nonce_len| and the limit for |plaintext_len|. + if (plaintext_len > CRYPTO_ccm128_max_input(ctx) || + nonce_len != 15 - L) { + return 0; + } + + // Assemble the first block for computing the MAC. + OPENSSL_memset(state, 0, sizeof(*state)); + state->nonce.c[0] = (uint8_t)((L - 1) | ((M - 2) / 2) << 3); + if (aad_len != 0) { + state->nonce.c[0] |= 0x40; // Set AAD Flag + } + OPENSSL_memcpy(&state->nonce.c[1], nonce, nonce_len); + for (unsigned i = 0; i < L; i++) { + state->nonce.c[15 - i] = (uint8_t)(plaintext_len >> (8 * i)); + } + + (*block)(state->nonce.c, state->cmac.c, key); + size_t blocks = 1; + + if (aad_len != 0) { + unsigned i; + // Cast to u64 to avoid the compiler complaining about invalid shifts. + uint64_t aad_len_u64 = aad_len; + if (aad_len_u64 < 0x10000 - 0x100) { + state->cmac.c[0] ^= (uint8_t)(aad_len >> 8); + state->cmac.c[1] ^= (uint8_t)aad_len; + i = 2; + } else if (aad_len_u64 <= 0xffffffff) { + state->cmac.c[0] ^= 0xff; + state->cmac.c[1] ^= 0xfe; + state->cmac.c[2] ^= (uint8_t)(aad_len >> 24); + state->cmac.c[3] ^= (uint8_t)(aad_len >> 16); + state->cmac.c[4] ^= (uint8_t)(aad_len >> 8); + state->cmac.c[5] ^= (uint8_t)aad_len; + i = 6; + } else { + state->cmac.c[0] ^= 0xff; + state->cmac.c[1] ^= 0xff; + state->cmac.c[2] ^= (uint8_t)(aad_len >> (56 % (sizeof(aad_len) * 8))); + state->cmac.c[3] ^= (uint8_t)(aad_len >> (48 % (sizeof(aad_len) * 8))); + state->cmac.c[4] ^= (uint8_t)(aad_len >> (40 % (sizeof(aad_len) * 8))); + state->cmac.c[5] ^= (uint8_t)(aad_len >> (32 % (sizeof(aad_len) * 8))); + state->cmac.c[6] ^= (uint8_t)(aad_len >> 24); + state->cmac.c[7] ^= (uint8_t)(aad_len >> 16); + state->cmac.c[8] ^= (uint8_t)(aad_len >> 8); + state->cmac.c[9] ^= (uint8_t)aad_len; + i = 10; + } + + do { + for (; i < 16 && aad_len != 0; i++) { + state->cmac.c[i] ^= *aad; + aad++; + aad_len--; + } + (*block)(state->cmac.c, state->cmac.c, key); + blocks++; + i = 0; + } while (aad_len != 0); + } + + // Per RFC 3610, section 2.6, the total number of block cipher operations done + // must not exceed 2^61. There are two block cipher operations remaining per + // message block, plus one block at the end to encrypt the MAC. + size_t remaining_blocks = 2 * ((plaintext_len + 15) / 16) + 1; + if (plaintext_len + 15 < plaintext_len || + remaining_blocks + blocks < blocks || + // Silence Clang's unhelpful -Wtautological-constant-out-of-range-compare + // warning. + (sizeof(size_t) > 4 && remaining_blocks + blocks > UINT64_C(1) << 61)) { + return 0; + } + + // Assemble the first block for encrypting and decrypting. The bottom |L| + // bytes are replaced with a counter and all bit the encoding of |L| is + // cleared in the first byte. + state->nonce.c[0] &= 7; + return 1; +} + +static int ccm128_encrypt(const CCM128_CONTEXT *ctx, struct ccm128_state *state, + const void *key, uint8_t *out, const uint8_t *in, + size_t len) { + // The counter for encryption begins at one. + for (unsigned i = 0; i < ctx->L; i++) { + state->nonce.c[15 - i] = 0; + } + state->nonce.c[15] = 1; + + uint8_t partial_buf[16]; + unsigned num = 0; + if (ctx->ctr != NULL) { + CRYPTO_ctr128_encrypt_ctr32(in, out, len, key, state->nonce.c, partial_buf, + &num, ctx->ctr); + } else { + CRYPTO_ctr128_encrypt(in, out, len, key, state->nonce.c, partial_buf, &num, + ctx->block); + } + return 1; +} + +static int ccm128_compute_mac(const CCM128_CONTEXT *ctx, + struct ccm128_state *state, const void *key, + uint8_t *out_tag, size_t tag_len, + const uint8_t *in, size_t len) { + block128_f block = ctx->block; + if (tag_len != ctx->M) { + return 0; + } + + // Incorporate |in| into the MAC. + union { + uint64_t u[2]; + uint8_t c[16]; + } tmp; + while (len >= 16) { + OPENSSL_memcpy(tmp.c, in, 16); + state->cmac.u[0] ^= tmp.u[0]; + state->cmac.u[1] ^= tmp.u[1]; + (*block)(state->cmac.c, state->cmac.c, key); + in += 16; + len -= 16; + } + if (len > 0) { + for (size_t i = 0; i < len; i++) { + state->cmac.c[i] ^= in[i]; + } + (*block)(state->cmac.c, state->cmac.c, key); + } + + // Encrypt the MAC with counter zero. + for (unsigned i = 0; i < ctx->L; i++) { + state->nonce.c[15 - i] = 0; + } + (*block)(state->nonce.c, tmp.c, key); + state->cmac.u[0] ^= tmp.u[0]; + state->cmac.u[1] ^= tmp.u[1]; + + OPENSSL_memcpy(out_tag, state->cmac.c, tag_len); + return 1; +} + +int CRYPTO_ccm128_encrypt(const CCM128_CONTEXT *ctx, const void *key, + uint8_t *out, uint8_t *out_tag, size_t tag_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t len, const uint8_t *aad, + size_t aad_len) { + struct ccm128_state state; + return ccm128_init_state(ctx, &state, key, nonce, nonce_len, aad, aad_len, + len) && + ccm128_compute_mac(ctx, &state, key, out_tag, tag_len, in, len) && + ccm128_encrypt(ctx, &state, key, out, in, len); +} + +int CRYPTO_ccm128_decrypt(const CCM128_CONTEXT *ctx, const void *key, + uint8_t *out, uint8_t *out_tag, size_t tag_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t len, const uint8_t *aad, + size_t aad_len) { + struct ccm128_state state; + return ccm128_init_state(ctx, &state, key, nonce, nonce_len, aad, aad_len, + len) && + ccm128_encrypt(ctx, &state, key, out, in, len) && + ccm128_compute_mac(ctx, &state, key, out_tag, tag_len, out, len); +} diff --git a/crypto/fipsmodule/modes/internal.h b/crypto/fipsmodule/modes/internal.h index 68ef4dcc..de6c5035 100644 --- a/crypto/fipsmodule/modes/internal.h +++ b/crypto/fipsmodule/modes/internal.h @@ -249,6 +249,42 @@ OPENSSL_EXPORT void CRYPTO_gcm128_tag(GCM128_CONTEXT *ctx, uint8_t *tag, size_t len); +// CCM. + +typedef struct ccm128_context { + block128_f block; + ctr128_f ctr; + unsigned M, L; +} CCM128_CONTEXT; + +// CRYPTO_ccm128_init initialises |ctx| to use |block| (typically AES) with the +// specified |M| and |L| parameters. It returns one on success and zero if |M| +// or |L| is invalid. +int CRYPTO_ccm128_init(CCM128_CONTEXT *ctx, const void *key, block128_f block, + ctr128_f ctr, unsigned M, unsigned L); + +// CRYPTO_ccm128_max_input returns the maximum input length accepted by |ctx|. +size_t CRYPTO_ccm128_max_input(const CCM128_CONTEXT *ctx); + +// CRYPTO_ccm128_encrypt encrypts |len| bytes from |in| to |out| writing the tag +// to |out_tag|. |key| must be the same key that was passed to +// |CRYPTO_ccm128_init|. It returns one on success and zero otherwise. +int CRYPTO_ccm128_encrypt(const CCM128_CONTEXT *ctx, const void *key, + uint8_t *out, uint8_t *out_tag, size_t tag_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t len, const uint8_t *aad, + size_t aad_len); + +// CRYPTO_ccm128_decrypt decrypts |len| bytes from |in| to |out|, writing the +// expected tag to |out_tag|. |key| must be the same key that was passed to +// |CRYPTO_ccm128_init|. It returns one on success and zero otherwise. +int CRYPTO_ccm128_decrypt(const CCM128_CONTEXT *ctx, const void *key, + uint8_t *out, uint8_t *out_tag, size_t tag_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t len, const uint8_t *aad, + size_t aad_len); + + // CBC. // cbc128_f is the type of a function that performs CBC-mode encryption. diff --git a/include/openssl/aead.h b/include/openssl/aead.h index 7424e29c..2b45d201 100644 --- a/include/openssl/aead.h +++ b/include/openssl/aead.h @@ -117,6 +117,10 @@ OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_gcm_siv(void); // https://tools.ietf.org/html/draft-irtf-cfrg-gcmsiv-02 OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_gcm_siv(void); +// EVP_aead_aes_128_ccm_bluetooth is AES-128-CCM with M=4 and L=2, as decribed +// in the Bluetooth Core Specification v5.0, Volume 6, Part E, Section 1. +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_ccm_bluetooth(void); + // EVP_has_aes_hardware returns one if we enable hardware support for fast and // constant-time AES-GCM. OPENSSL_EXPORT int EVP_has_aes_hardware(void); diff --git a/sources.cmake b/sources.cmake index 46b5cc04..f24ba20e 100644 --- a/sources.cmake +++ b/sources.cmake @@ -10,6 +10,7 @@ set( crypto/cipher_extra/test/aes_128_cbc_sha1_tls_implicit_iv_tests.txt crypto/cipher_extra/test/aes_128_cbc_sha1_tls_tests.txt crypto/cipher_extra/test/aes_128_cbc_sha256_tls_tests.txt + crypto/cipher_extra/test/aes_128_ccm_bluetooth_tests.txt crypto/cipher_extra/test/aes_128_ctr_hmac_sha256.txt crypto/cipher_extra/test/aes_128_gcm_siv_tests.txt crypto/cipher_extra/test/aes_128_gcm_tests.txt diff --git a/tool/speed.cc b/tool/speed.cc index 87aa2de9..f4b452fc 100644 --- a/tool/speed.cc +++ b/tool/speed.cc @@ -709,6 +709,8 @@ bool Speed(const std::vector &args) { selected) || !SpeedAEADOpen(EVP_aead_aes_256_gcm_siv(), "AES-256-GCM-SIV", kTLSADLen, selected) || + !SpeedAEAD(EVP_aead_aes_128_ccm_bluetooth(), "AES-128-CCM-Bluetooth", + kTLSADLen, selected) || !SpeedHash(EVP_sha1(), "SHA-1", selected) || !SpeedHash(EVP_sha256(), "SHA-256", selected) || !SpeedHash(EVP_sha512(), "SHA-512", selected) ||