From 4ea59711d24ad3103a39321ce18be58baed0ce8f Mon Sep 17 00:00:00 2001 From: Trond Einar Snekvik Date: Wed, 29 Jan 2020 13:03:23 +0100 Subject: [PATCH] Bluetooth: Move Mesh CCM into a separate module Moves the Mesh AES-CCM module out into a separate module, to make it accessible from other subsystems. Adds the new CCM API in include/bluetooth/crypto.h along with the bt_encrypt functions. Signed-off-by: Trond Einar Snekvik --- include/bluetooth/crypto.h | 51 +++++- subsys/bluetooth/host/CMakeLists.txt | 1 + subsys/bluetooth/host/Kconfig | 9 +- subsys/bluetooth/host/aes_ccm.c | 231 ++++++++++++++++++++++++++ subsys/bluetooth/mesh/Kconfig | 1 + subsys/bluetooth/mesh/crypto.c | 237 ++------------------------- 6 files changed, 301 insertions(+), 229 deletions(-) create mode 100644 subsys/bluetooth/host/aes_ccm.c diff --git a/include/bluetooth/crypto.h b/include/bluetooth/crypto.h index 4f2034c4068..32e9d5e69f9 100644 --- a/include/bluetooth/crypto.h +++ b/include/bluetooth/crypto.h @@ -3,7 +3,7 @@ */ /* - * Copyright (c) 2017 Nordic Semiconductor ASA + * Copyright (c) 2017-2020 Nordic Semiconductor ASA * Copyright (c) 2015-2017 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 @@ -67,6 +67,55 @@ int bt_encrypt_le(const u8_t key[16], const u8_t plaintext[16], int bt_encrypt_be(const u8_t key[16], const u8_t plaintext[16], u8_t enc_data[16]); + +/** @brief Decrypt big-endian data with AES-CCM. + * + * Decrypts and authorizes @c enc_data with AES-CCM, as described in + * https://tools.ietf.org/html/rfc3610. + * + * Assumes that the MIC follows directly after the encrypted data. + * + * @param key 128 bit MS byte first key + * @param nonce 13 byte MS byte first nonce + * @param enc_data Encrypted data + * @param len Length of the encrypted data + * @param aad Additional input data + * @param aad_len Additional input data length + * @param plaintext Plaintext buffer to place result in + * @param mic_size Size of the trailing MIC (in bytes) + * + * @retval 0 Successfully decrypted the data. + * @retval -EINVAL Invalid parameters. + * @retval -EBADMSG Authentication failed. + */ +int bt_ccm_decrypt(const u8_t key[16], u8_t nonce[13], const u8_t *enc_data, + size_t len, const u8_t *aad, size_t aad_len, + u8_t *plaintext, size_t mic_size); + + +/** @brief Encrypt big-endian data with AES-CCM. + * + * Encrypts and generates a MIC from @c plaintext with AES-CCM, as described in + * https://tools.ietf.org/html/rfc3610. + * + * Places the MIC directly after the encrypted data. + * + * @param key 128 bit MS byte first key + * @param nonce 13 byte MS byte first nonce + * @param enc_data Buffer to place encrypted data in + * @param len Length of the encrypted data + * @param aad Additional input data + * @param aad_len Additional input data length + * @param plaintext Plaintext buffer to encrypt + * @param mic_size Size of the trailing MIC (in bytes) + * + * @retval 0 Successfully encrypted the data. + * @retval -EINVAL Invalid parameters. + */ +int bt_ccm_encrypt(const u8_t key[16], u8_t nonce[13], const u8_t *enc_data, + size_t len, const u8_t *aad, size_t aad_len, + u8_t *plaintext, size_t mic_size); + #ifdef __cplusplus } #endif diff --git a/subsys/bluetooth/host/CMakeLists.txt b/subsys/bluetooth/host/CMakeLists.txt index 5edfb9491b8..013f39a8912 100644 --- a/subsys/bluetooth/host/CMakeLists.txt +++ b/subsys/bluetooth/host/CMakeLists.txt @@ -11,6 +11,7 @@ zephyr_library_sources_ifdef(CONFIG_BT_AVDTP avdtp.c) zephyr_library_sources_ifdef(CONFIG_BT_RFCOMM rfcomm.c) zephyr_library_sources_ifdef(CONFIG_BT_TESTING testing.c) zephyr_library_sources_ifdef(CONFIG_BT_SETTINGS settings.c) +zephyr_library_sources_ifdef(CONFIG_BT_HOST_CCM aes_ccm.c) zephyr_library_sources_ifdef( CONFIG_BT_BREDR diff --git a/subsys/bluetooth/host/Kconfig b/subsys/bluetooth/host/Kconfig index 4a08327f9fb..a8a355aa6e1 100644 --- a/subsys/bluetooth/host/Kconfig +++ b/subsys/bluetooth/host/Kconfig @@ -1,6 +1,6 @@ # Bluetooth LE stack configuration options -# Copyright (c) 2016-2017 Nordic Semiconductor ASA +# Copyright (c) 2016-2020 Nordic Semiconductor ASA # Copyright (c) 2015-2016 Intel Corporation # SPDX-License-Identifier: Apache-2.0 @@ -541,6 +541,13 @@ config BT_TINYCRYPT_ECC to enabled for a combined build with Zephyr's own controller, since it does not have any special ECC support itself (at least not currently). +config BT_HOST_CCM + bool "Enable host side AES-CCM module" + help + Enables the software based AES-CCM engine in the host. Will use the + controller's AES encryption functions if available, or BT_HOST_CRYPTO + otherwise. + if BT_DEBUG config BT_DEBUG_SETTINGS bool "Bluetooth storage debug" diff --git a/subsys/bluetooth/host/aes_ccm.c b/subsys/bluetooth/host/aes_ccm.c new file mode 100644 index 00000000000..f6e01c9b2ee --- /dev/null +++ b/subsys/bluetooth/host/aes_ccm.c @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2020 Nordic Semiconductor ASA + * Copyright (c) 2017 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include +#include + +#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_CORE) +#define LOG_MODULE_NAME bt_aes_ccm +#include "common/log.h" + +static inline void xor16(u8_t *dst, const u8_t *a, const u8_t *b) +{ + dst[0] = a[0] ^ b[0]; + dst[1] = a[1] ^ b[1]; + dst[2] = a[2] ^ b[2]; + dst[3] = a[3] ^ b[3]; + dst[4] = a[4] ^ b[4]; + dst[5] = a[5] ^ b[5]; + dst[6] = a[6] ^ b[6]; + dst[7] = a[7] ^ b[7]; + dst[8] = a[8] ^ b[8]; + dst[9] = a[9] ^ b[9]; + dst[10] = a[10] ^ b[10]; + dst[11] = a[11] ^ b[11]; + dst[12] = a[12] ^ b[12]; + dst[13] = a[13] ^ b[13]; + dst[14] = a[14] ^ b[14]; + dst[15] = a[15] ^ b[15]; +} + +/* pmsg is assumed to have the nonce already present in bytes 1-13 */ +static int ccm_calculate_X0(const u8_t key[16], const u8_t *aad, u8_t aad_len, + size_t mic_size, u8_t msg_len, u8_t b[16], + u8_t X0[16]) +{ + int i, j, err; + + /* X_0 = e(AppKey, flags || nonce || length) */ + b[0] = (((mic_size - 2) / 2) << 3) | ((!!aad_len) << 6) | 0x01; + + sys_put_be16(msg_len, b + 14); + + err = bt_encrypt_be(key, b, X0); + if (err) { + return err; + } + + /* If AAD is being used to authenticate, include it here */ + if (aad_len) { + sys_put_be16(aad_len, b); + + for (i = 0; i < sizeof(u16_t); i++) { + b[i] = X0[i] ^ b[i]; + } + + j = 0; + aad_len += sizeof(u16_t); + while (aad_len > 16) { + do { + b[i] = X0[i] ^ aad[j]; + i++, j++; + } while (i < 16); + + aad_len -= 16; + i = 0; + + err = bt_encrypt_be(key, b, X0); + if (err) { + return err; + } + } + + for (; i < aad_len; i++, j++) { + b[i] = X0[i] ^ aad[j]; + } + + for (i = aad_len; i < 16; i++) { + b[i] = X0[i]; + } + + err = bt_encrypt_be(key, b, X0); + if (err) { + return err; + } + } + + return 0; +} + +static int ccm_auth(const u8_t key[16], u8_t nonce[13], + const u8_t *cleartext_msg, size_t msg_len, const u8_t *aad, + size_t aad_len, u8_t *mic, size_t mic_size) +{ + u8_t b[16], Xn[16], s0[16]; + u16_t blk_cnt, last_blk; + int err, j, i; + + last_blk = msg_len % 16; + blk_cnt = (msg_len + 15) / 16; + if (!last_blk) { + last_blk = 16U; + } + + b[0] = 0x01; + memcpy(b + 1, nonce, 13); + + /* S[0] = e(AppKey, 0x01 || nonce || 0x0000) */ + sys_put_be16(0x0000, &b[14]); + + err = bt_encrypt_be(key, b, s0); + if (err) { + return err; + } + + ccm_calculate_X0(key, aad, aad_len, mic_size, msg_len, b, Xn); + + for (j = 0; j < blk_cnt; j++) { + /* X_1 = e(AppKey, X_0 ^ Payload[0-15]) */ + if (j + 1 == blk_cnt) { + for (i = 0; i < last_blk; i++) { + b[i] = Xn[i] ^ cleartext_msg[(j * 16) + i]; + } + + memcpy(&b[i], &Xn[i], 16 - i); + } else { + xor16(b, Xn, &cleartext_msg[j * 16]); + } + + err = bt_encrypt_be(key, b, Xn); + if (err) { + return err; + } + } + + /* MIC = C_mic ^ X_1 */ + for (i = 0; i < mic_size; i++) { + mic[i] = s0[i] ^ Xn[i]; + } + + return 0; +} + +static int ccm_crypt(const u8_t key[16], const u8_t nonce[13], + const u8_t *in_msg, u8_t *out_msg, size_t msg_len) +{ + u8_t a_i[16], s_i[16]; + u16_t last_blk, blk_cnt; + size_t i, j; + int err; + + last_blk = msg_len % 16; + blk_cnt = (msg_len + 15) / 16; + if (!last_blk) { + last_blk = 16U; + } + + a_i[0] = 0x01; + memcpy(&a_i[1], nonce, 13); + + for (j = 0; j < blk_cnt; j++) { + /* S_1 = e(AppKey, 0x01 || nonce || 0x0001) */ + sys_put_be16(j + 1, &a_i[14]); + + err = bt_encrypt_be(key, a_i, s_i); + if (err) { + return err; + } + + /* Encrypted = Payload[0-15] ^ C_1 */ + if (j < blk_cnt - 1) { + xor16(&out_msg[j * 16], s_i, &in_msg[j * 16]); + } else { + for (i = 0; i < last_blk; i++) { + out_msg[(j * 16) + i] = + in_msg[(j * 16) + i] ^ s_i[i]; + } + } + } + return 0; +} + +int bt_ccm_decrypt(const u8_t key[16], u8_t nonce[13], const u8_t *enc_msg, + size_t msg_len, const u8_t *aad, size_t aad_len, + u8_t *out_msg, size_t mic_size) +{ + u8_t mic[16]; + + if (aad_len >= 0xff00 || mic_size > sizeof(mic)) { + return -EINVAL; + } + + ccm_crypt(key, nonce, enc_msg, out_msg, msg_len); + + ccm_auth(key, nonce, out_msg, msg_len, aad, aad_len, mic, mic_size); + + if (memcmp(mic, enc_msg + msg_len, mic_size)) { + return -EBADMSG; + } + + return 0; +} + +int bt_ccm_encrypt(const u8_t key[16], u8_t nonce[13], const u8_t *msg, + size_t msg_len, const u8_t *aad, size_t aad_len, + u8_t *out_msg, size_t mic_size) +{ + u8_t *mic = out_msg + msg_len; + + BT_DBG("key %s", bt_hex(key, 16)); + BT_DBG("nonce %s", bt_hex(nonce, 13)); + BT_DBG("msg (len %zu) %s", msg_len, bt_hex(msg, msg_len)); + BT_DBG("aad_len %zu mic_size %zu", aad_len, mic_size); + + /* Unsupported AAD size */ + if (aad_len >= 0xff00 || mic_size > 16) { + return -EINVAL; + } + + ccm_auth(key, nonce, out_msg, msg_len, aad, aad_len, mic, mic_size); + + ccm_crypt(key, nonce, msg, out_msg, msg_len); + + return 0; +} diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index f7bec8d3404..ff8d9d04b4f 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -8,6 +8,7 @@ menuconfig BT_MESH select TINYCRYPT select TINYCRYPT_AES select TINYCRYPT_AES_CMAC + select BT_HOST_CCM depends on BT_OBSERVER && BT_BROADCASTER help This option enables Bluetooth Mesh support. The specific diff --git a/subsys/bluetooth/mesh/crypto.c b/subsys/bluetooth/mesh/crypto.c index ace71e19f02..ba565bc4358 100644 --- a/subsys/bluetooth/mesh/crypto.c +++ b/subsys/bluetooth/mesh/crypto.c @@ -203,223 +203,6 @@ int bt_mesh_id128(const u8_t n[16], const char *s, u8_t out[16]) return bt_mesh_k1(n, 16, salt, id128, out); } -static inline void xor16(u8_t *dst, const u8_t *a, const u8_t *b) -{ - dst[0] = a[0] ^ b[0]; - dst[1] = a[1] ^ b[1]; - dst[2] = a[2] ^ b[2]; - dst[3] = a[3] ^ b[3]; - dst[4] = a[4] ^ b[4]; - dst[5] = a[5] ^ b[5]; - dst[6] = a[6] ^ b[6]; - dst[7] = a[7] ^ b[7]; - dst[8] = a[8] ^ b[8]; - dst[9] = a[9] ^ b[9]; - dst[10] = a[10] ^ b[10]; - dst[11] = a[11] ^ b[11]; - dst[12] = a[12] ^ b[12]; - dst[13] = a[13] ^ b[13]; - dst[14] = a[14] ^ b[14]; - dst[15] = a[15] ^ b[15]; -} - -/* pmsg is assumed to have the nonce already present in bytes 1-13 */ -static int ccm_calculate_X0(const u8_t key[16], const u8_t *aad, u8_t aad_len, - size_t mic_size, u8_t msg_len, u8_t b[16], - u8_t X0[16]) -{ - int i, j, err; - - /* X_0 = e(AppKey, flags || nonce || length) */ - b[0] = (((mic_size - 2) / 2) << 3) | ((!!aad_len) << 6) | 0x01; - - sys_put_be16(msg_len, b + 14); - - err = bt_encrypt_be(key, b, X0); - if (err) { - return err; - } - - /* If AAD is being used to authenticate, include it here */ - if (aad_len) { - sys_put_be16(aad_len, b); - - for (i = 0; i < sizeof(u16_t); i++) { - b[i] = X0[i] ^ b[i]; - } - - j = 0; - aad_len += sizeof(u16_t); - while (aad_len > 16) { - do { - b[i] = X0[i] ^ aad[j]; - i++, j++; - } while (i < 16); - - aad_len -= 16; - i = 0; - - err = bt_encrypt_be(key, b, X0); - if (err) { - return err; - } - } - - for (; i < aad_len; i++, j++) { - b[i] = X0[i] ^ aad[j]; - } - - for (i = aad_len; i < 16; i++) { - b[i] = X0[i]; - } - - err = bt_encrypt_be(key, b, X0); - if (err) { - return err; - } - } - - return 0; -} - -static int ccm_auth(const u8_t key[16], u8_t nonce[13], - const u8_t *cleartext_msg, size_t msg_len, const u8_t *aad, - size_t aad_len, u8_t *mic, size_t mic_size) -{ - u8_t b[16], Xn[16], s0[16]; - u16_t blk_cnt, last_blk; - int err, j, i; - - last_blk = msg_len % 16; - blk_cnt = (msg_len + 15) / 16; - if (!last_blk) { - last_blk = 16U; - } - - b[0] = 0x01; - memcpy(b + 1, nonce, 13); - - /* S[0] = e(AppKey, 0x01 || nonce || 0x0000) */ - sys_put_be16(0x0000, &b[14]); - - err = bt_encrypt_be(key, b, s0); - if (err) { - return err; - } - - ccm_calculate_X0(key, aad, aad_len, mic_size, msg_len, b, Xn); - - for (j = 0; j < blk_cnt; j++) { - /* X_1 = e(AppKey, X_0 ^ Payload[0-15]) */ - if (j + 1 == blk_cnt) { - for (i = 0; i < last_blk; i++) { - b[i] = Xn[i] ^ cleartext_msg[(j * 16) + i]; - } - - memcpy(&b[i], &Xn[i], 16 - i); - } else { - xor16(b, Xn, &cleartext_msg[j * 16]); - } - - err = bt_encrypt_be(key, b, Xn); - if (err) { - return err; - } - } - - /* MIC = C_mic ^ X_1 */ - for (i = 0; i < mic_size; i++) { - mic[i] = s0[i] ^ Xn[i]; - } - - return 0; -} - -static int ccm_crypt(const u8_t key[16], const u8_t nonce[13], - const u8_t *in_msg, u8_t *out_msg, size_t msg_len) -{ - u8_t a_i[16], s_i[16]; - u16_t last_blk, blk_cnt; - size_t i, j; - int err; - - last_blk = msg_len % 16; - blk_cnt = (msg_len + 15) / 16; - if (!last_blk) { - last_blk = 16U; - } - - a_i[0] = 0x01; - memcpy(&a_i[1], nonce, 13); - - for (j = 0; j < blk_cnt; j++) { - /* S_1 = e(AppKey, 0x01 || nonce || 0x0001) */ - sys_put_be16(j + 1, &a_i[14]); - - err = bt_encrypt_be(key, a_i, s_i); - if (err) { - return err; - } - - /* Encrypted = Payload[0-15] ^ C_1 */ - if (j < blk_cnt - 1) { - xor16(&out_msg[j * 16], s_i, &in_msg[j * 16]); - } else { - for (i = 0; i < last_blk; i++) { - out_msg[(j * 16) + i] = - in_msg[(j * 16) + i] ^ s_i[i]; - } - } - } - return 0; -} - -static int bt_mesh_ccm_decrypt(const u8_t key[16], u8_t nonce[13], - const u8_t *enc_msg, size_t msg_len, - const u8_t *aad, size_t aad_len, - u8_t *out_msg, size_t mic_size) -{ - u8_t mic[16]; - - if (msg_len == 0 || aad_len >= 0xff00) { - return -EINVAL; - } - - ccm_crypt(key, nonce, enc_msg, out_msg, msg_len); - - ccm_auth(key, nonce, out_msg, msg_len, aad, aad_len, mic, mic_size); - - if (memcmp(mic, enc_msg + msg_len, mic_size)) { - return -EBADMSG; - } - - return 0; -} - -static int bt_mesh_ccm_encrypt(const u8_t key[16], u8_t nonce[13], - const u8_t *msg, size_t msg_len, - const u8_t *aad, size_t aad_len, - u8_t *out_msg, size_t mic_size) -{ - u8_t *mic = out_msg + msg_len; - - BT_DBG("key %s", bt_hex(key, 16)); - BT_DBG("nonce %s", bt_hex(nonce, 13)); - BT_DBG("msg (len %zu) %s", msg_len, bt_hex(msg, msg_len)); - BT_DBG("aad_len %zu mic_size %zu", aad_len, mic_size); - - /* Unsupported AAD size */ - if (aad_len >= 0xff00) { - return -EINVAL; - } - - ccm_auth(key, nonce, out_msg, msg_len, aad, aad_len, mic, mic_size); - - ccm_crypt(key, nonce, msg, out_msg, msg_len); - - return 0; -} - static void create_proxy_nonce(u8_t nonce[13], const u8_t *pdu, u32_t iv_index) { @@ -517,8 +300,8 @@ int bt_mesh_net_encrypt(const u8_t key[16], struct net_buf_simple *buf, BT_DBG("Nonce %s", bt_hex(nonce, 13)); - err = bt_mesh_ccm_encrypt(key, nonce, &buf->data[7], buf->len - 7, - NULL, 0, &buf->data[7], mic_len); + err = bt_ccm_encrypt(key, nonce, &buf->data[7], buf->len - 7, NULL, 0, + &buf->data[7], mic_len); if (!err) { net_buf_simple_add(buf, mic_len); } @@ -546,8 +329,8 @@ int bt_mesh_net_decrypt(const u8_t key[16], struct net_buf_simple *buf, buf->len -= mic_len; - return bt_mesh_ccm_decrypt(key, nonce, &buf->data[7], buf->len - 7, - NULL, 0, &buf->data[7], mic_len); + return bt_ccm_decrypt(key, nonce, &buf->data[7], buf->len - 7, NULL, 0, + &buf->data[7], mic_len); } static void create_app_nonce(u8_t nonce[13], bool dev_key, u8_t aszmic, @@ -584,8 +367,8 @@ int bt_mesh_app_encrypt(const u8_t key[16], bool dev_key, u8_t aszmic, BT_DBG("Nonce %s", bt_hex(nonce, 13)); - err = bt_mesh_ccm_encrypt(key, nonce, buf->data, buf->len, ad, - ad ? 16 : 0, buf->data, APP_MIC_LEN(aszmic)); + err = bt_ccm_encrypt(key, nonce, buf->data, buf->len, ad, ad ? 16 : 0, + buf->data, APP_MIC_LEN(aszmic)); if (!err) { net_buf_simple_add(buf, APP_MIC_LEN(aszmic)); BT_DBG("Encr: %s", bt_hex(buf->data, buf->len)); @@ -609,8 +392,8 @@ int bt_mesh_app_decrypt(const u8_t key[16], bool dev_key, u8_t aszmic, BT_DBG("AppKey %s", bt_hex(key, 16)); BT_DBG("Nonce %s", bt_hex(nonce, 13)); - err = bt_mesh_ccm_decrypt(key, nonce, buf->data, buf->len, ad, - ad ? 16 : 0, out->data, APP_MIC_LEN(aszmic)); + err = bt_ccm_decrypt(key, nonce, buf->data, buf->len, ad, ad ? 16 : 0, + out->data, APP_MIC_LEN(aszmic)); if (!err) { net_buf_simple_add(out, buf->len); } @@ -736,13 +519,13 @@ int bt_mesh_prov_conf(const u8_t conf_key[16], const u8_t rand[16], int bt_mesh_prov_decrypt(const u8_t key[16], u8_t nonce[13], const u8_t data[25 + 8], u8_t out[25]) { - return bt_mesh_ccm_decrypt(key, nonce, data, 25, NULL, 0, out, 8); + return bt_ccm_decrypt(key, nonce, data, 25, NULL, 0, out, 8); } int bt_mesh_prov_encrypt(const u8_t key[16], u8_t nonce[13], const u8_t data[25], u8_t out[25 + 8]) { - return bt_mesh_ccm_encrypt(key, nonce, data, 25, NULL, 0, out, 8); + return bt_ccm_encrypt(key, nonce, data, 25, NULL, 0, out, 8); } int bt_mesh_beacon_auth(const u8_t beacon_key[16], u8_t flags,