Bluetooth: Make LE Encrypt helpers public

Expose LE Encrypt helpers to applications. If software-
based controller is compiled-in, then controller's AES
hardware will be used by the exposed helper interface.

Change-id: I2bac9dfa5ccb3dd50447079affb52d920ae5bd81
Signed-off-by: Vinayak Chettimada <vinayak.kariappa.chettimada@nordicsemi.no>.
This commit is contained in:
Vinayak Chettimada 2017-03-15 11:19:27 +01:00 committed by Johan Hedberg
commit a91dd34830
8 changed files with 202 additions and 125 deletions

View file

@ -3,6 +3,7 @@
*/ */
/* /*
* Copyright (c) 2017 Nordic Semiconductor ASA
* Copyright (c) 2015-2016 Intel Corporation * Copyright (c) 2015-2016 Intel Corporation
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
@ -469,6 +470,21 @@ int bt_br_set_connectable(bool enable);
*/ */
int bt_rand(void *buf, size_t len); int bt_rand(void *buf, size_t len);
/** @brief AES encrypt data.
*
* An AES encrypt helper is used to request the Bluetooth controller's own
* hardware to encrypt the plaintext using the key and returns the encrypted
* data.
*
* @param key 128 bit LS byte first key for the encryption of the plaintext
* @param plaintext 128 bit LS byte first plaintext data block to be encrypted
* @param enc_data 128 bit LS byte first encrypted data block
*
* @return Zero on success or error code otherwise.
*/
int bt_encrypt(const uint8_t key[16], const uint8_t plaintext[16],
uint8_t enc_data[16]);
/** /**
* @} * @}
*/ */

View file

@ -5,8 +5,13 @@
*/ */
#include <soc.h> #include <soc.h>
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BLUETOOTH_DEBUG_HCI_DRIVER)
#include <bluetooth/log.h>
#include "hal/cpu.h" #include "hal/cpu.h"
#include "hal/rand.h" #include "hal/rand.h"
#include "hal/ecb.h"
K_MUTEX_DEFINE(mutex_rand); K_MUTEX_DEFINE(mutex_rand);
@ -23,3 +28,15 @@ int bt_rand(void *buf, size_t len)
return 0; return 0;
} }
int bt_encrypt(const uint8_t key[16], const uint8_t plaintext[16],
uint8_t enc_data[16])
{
BT_DBG("key %s plaintext %s", bt_hex(key, 16), bt_hex(plaintext, 16));
ecb_encrypt(key, plaintext, enc_data, NULL);
BT_DBG("enc_data %s", bt_hex(enc_data, 16));
return 0;
}

View file

@ -31,10 +31,6 @@ config BLUETOOTH_HCI_HOST
default y default y
depends on !BLUETOOTH_HCI_RAW depends on !BLUETOOTH_HCI_RAW
select POLL select POLL
select TINYCRYPT if !BLUETOOTH_CONTROLLER
select TINYCRYPT_SHA256 if !BLUETOOTH_CONTROLLER
select TINYCRYPT_SHA256_HMAC if !BLUETOOTH_CONTROLLER
select TINYCRYPT_SHA256_HMAC_PRNG if !BLUETOOTH_CONTROLLER
config BLUETOOTH_RECV_IS_RX_THREAD config BLUETOOTH_RECV_IS_RX_THREAD
# Virtual option set by the HCI driver to indicate that there's # Virtual option set by the HCI driver to indicate that there's
@ -99,6 +95,18 @@ config BLUETOOTH_RX_STACK_SIZE
accommodate for that. accommodate for that.
if BLUETOOTH_HCI_HOST if BLUETOOTH_HCI_HOST
config BLUETOOTH_HOST_CRYPTO
# Hidden option that compiles in random number generation and AES
# encryption support using TinyCrypt library if software-based
# controller is disabled.
bool
default y if !BLUETOOTH_CONTROLLER
select TINYCRYPT
select TINYCRYPT_AES
select TINYCRYPT_SHA256
select TINYCRYPT_SHA256_HMAC
select TINYCRYPT_SHA256_HMAC_PRNG
config BLUETOOTH_INTERNAL_STORAGE config BLUETOOTH_INTERNAL_STORAGE
bool "Use an internal persistent storage handler" bool "Use an internal persistent storage handler"
depends on FILE_SYSTEM depends on FILE_SYSTEM

View file

@ -31,3 +31,5 @@ ifeq ($(CONFIG_BLUETOOTH_CONN),y)
obj-$(CONFIG_BLUETOOTH_A2DP) += a2dp.o obj-$(CONFIG_BLUETOOTH_A2DP) += a2dp.o
endif endif
obj-$(CONFIG_BLUETOOTH_HOST_CRYPTO) += crypto.o

View file

@ -0,0 +1,135 @@
/*
* Copyright (c) 2017 Nordic Semiconductor ASA
* Copyright (c) 2015-2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <errno.h>
#include <zephyr.h>
#include <misc/byteorder.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/conn.h>
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BLUETOOTH_DEBUG_HCI_CORE)
#include <bluetooth/log.h>
#include "hci_core.h"
#include <tinycrypt/constants.h>
#include <tinycrypt/hmac_prng.h>
#include <tinycrypt/aes.h>
#include <tinycrypt/utils.h>
static struct tc_hmac_prng_struct prng;
static int prng_reseed(struct tc_hmac_prng_struct *h)
{
uint8_t seed[32];
int64_t extra;
int ret, i;
for (i = 0; i < (sizeof(seed) / 8); i++) {
struct bt_hci_rp_le_rand *rp;
struct net_buf *rsp;
ret = bt_hci_cmd_send_sync(BT_HCI_OP_LE_RAND, NULL, &rsp);
if (ret) {
return ret;
}
rp = (void *)rsp->data;
memcpy(&seed[i * 8], rp->rand, 8);
net_buf_unref(rsp);
}
extra = k_uptime_get();
ret = tc_hmac_prng_reseed(h, seed, sizeof(seed), (uint8_t *)&extra,
sizeof(extra));
if (ret == TC_CRYPTO_FAIL) {
BT_ERR("Failed to re-seed PRNG");
return -EIO;
}
return 0;
}
int prng_init(void)
{
struct bt_hci_rp_le_rand *rp;
struct net_buf *rsp;
int ret;
ret = bt_hci_cmd_send_sync(BT_HCI_OP_LE_RAND, NULL, &rsp);
if (ret) {
return ret;
}
rp = (void *)rsp->data;
ret = tc_hmac_prng_init(&prng, rp->rand, sizeof(rp->rand));
net_buf_unref(rsp);
if (ret == TC_CRYPTO_FAIL) {
BT_ERR("Failed to initialize PRNG");
return -EIO;
}
/* re-seed is needed after init */
return prng_reseed(&prng);
}
int bt_rand(void *buf, size_t len)
{
int ret;
ret = tc_hmac_prng_generate(buf, len, &prng);
if (ret == TC_HMAC_PRNG_RESEED_REQ) {
ret = prng_reseed(&prng);
if (ret) {
return ret;
}
ret = tc_hmac_prng_generate(buf, len, &prng);
}
if (ret == TC_CRYPTO_SUCCESS) {
return 0;
}
return -EIO;
}
int bt_encrypt(const uint8_t key[16], const uint8_t plaintext[16],
uint8_t enc_data[16])
{
struct tc_aes_key_sched_struct s;
uint8_t tmp[16];
BT_DBG("key %s plaintext %s", bt_hex(key, 16), bt_hex(plaintext, 16));
sys_memcpy_swap(tmp, key, 16);
if (tc_aes128_set_encrypt_key(&s, tmp) == TC_CRYPTO_FAIL) {
return -EINVAL;
}
sys_memcpy_swap(tmp, plaintext, 16);
if (tc_aes_encrypt(enc_data, tmp, &s) == TC_CRYPTO_FAIL) {
return -EINVAL;
}
sys_mem_swap(enc_data, 16);
BT_DBG("enc_data %s", bt_hex(enc_data, 16));
return 0;
}

View file

@ -0,0 +1,8 @@
/*
* Copyright (c) 2016-2017 Nordic Semiconductor ASA
* Copyright (c) 2015-2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
int prng_init(void);

View file

@ -1,6 +1,7 @@
/* hci_core.c - HCI core Bluetooth handling */ /* hci_core.c - HCI core Bluetooth handling */
/* /*
* Copyright (c) 2017 Nordic Semiconductor ASA
* Copyright (c) 2015-2016 Intel Corporation * Copyright (c) 2015-2016 Intel Corporation
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
@ -35,6 +36,10 @@
#include "l2cap_internal.h" #include "l2cap_internal.h"
#include "smp.h" #include "smp.h"
#if defined(CONFIG_BLUETOOTH_HOST_CRYPTO)
#include "crypto.h"
#endif
/* Peripheral timeout to initialize Connection Parameter Update procedure */ /* Peripheral timeout to initialize Connection Parameter Update procedure */
#define CONN_UPDATE_TIMEOUT K_SECONDS(5) #define CONN_UPDATE_TIMEOUT K_SECONDS(5)
#define RPA_TIMEOUT K_SECONDS(CONFIG_BLUETOOTH_RPA_TIMEOUT) #define RPA_TIMEOUT K_SECONDS(CONFIG_BLUETOOTH_RPA_TIMEOUT)
@ -2354,94 +2359,6 @@ static void hci_cmd_status(struct net_buf *buf)
} }
} }
#if !defined(CONFIG_BLUETOOTH_CONTROLLER)
#include <tinycrypt/constants.h>
#include <tinycrypt/hmac_prng.h>
#include <tinycrypt/utils.h>
static struct tc_hmac_prng_struct prng;
static int prng_reseed(struct tc_hmac_prng_struct *h)
{
uint8_t seed[32];
int64_t extra;
int ret, i;
for (i = 0; i < (sizeof(seed) / 8); i++) {
struct bt_hci_rp_le_rand *rp;
struct net_buf *rsp;
ret = bt_hci_cmd_send_sync(BT_HCI_OP_LE_RAND, NULL, &rsp);
if (ret) {
return ret;
}
rp = (void *)rsp->data;
memcpy(&seed[i * 8], rp->rand, 8);
net_buf_unref(rsp);
}
extra = k_uptime_get();
ret = tc_hmac_prng_reseed(h, seed, sizeof(seed), (uint8_t *)&extra,
sizeof(extra));
if (ret == TC_CRYPTO_FAIL) {
BT_ERR("Failed to re-seed PRNG");
return -EIO;
}
return 0;
}
static int prng_init(struct tc_hmac_prng_struct *h)
{
struct bt_hci_rp_le_rand *rp;
struct net_buf *rsp;
int ret;
ret = bt_hci_cmd_send_sync(BT_HCI_OP_LE_RAND, NULL, &rsp);
if (ret) {
return ret;
}
rp = (void *)rsp->data;
ret = tc_hmac_prng_init(h, rp->rand, sizeof(rp->rand));
net_buf_unref(rsp);
if (ret == TC_CRYPTO_FAIL) {
BT_ERR("Failed to initialize PRNG");
return -EIO;
}
/* re-seed is needed after init */
return prng_reseed(h);
}
int bt_rand(void *buf, size_t len)
{
int ret;
ret = tc_hmac_prng_generate(buf, len, &prng);
if (ret == TC_HMAC_PRNG_RESEED_REQ) {
ret = prng_reseed(&prng);
if (ret) {
return ret;
}
ret = tc_hmac_prng_generate(buf, len, &prng);
}
if (ret == TC_CRYPTO_SUCCESS) {
return 0;
}
return -EIO;
}
#endif /* !CONFIG_BLUETOOTH_CONTROLLER */
static int start_le_scan(uint8_t scan_type, uint16_t interval, uint16_t window, static int start_le_scan(uint8_t scan_type, uint16_t interval, uint16_t window,
uint8_t filter_dup) uint8_t filter_dup)
{ {
@ -2995,12 +2912,12 @@ static int common_init(void)
hci_reset_complete(rsp); hci_reset_complete(rsp);
net_buf_unref(rsp); net_buf_unref(rsp);
#if defined(CONFIG_BLUETOOTH_HOST_CRYPTO)
/* /*
* initialize PRNG right after reset so that it is safe to use it later * initialize PRNG right after reset so that it is safe to use it later
* on in initialization process * on in initialization process
*/ */
#if !defined(CONFIG_BLUETOOTH_CONTROLLER) err = prng_init();
err = prng_init(&prng);
if (err) { if (err) {
return err; return err;
} }

View file

@ -4,6 +4,7 @@
*/ */
/* /*
* Copyright (c) 2017 Nordic Semiconductor ASA
* Copyright (c) 2015-2016 Intel Corporation * Copyright (c) 2015-2016 Intel Corporation
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
@ -285,33 +286,6 @@ static uint8_t get_pair_method(struct bt_smp *smp, uint8_t remote_io)
return gen_method_sc[remote_io][get_io_capa()]; return gen_method_sc[remote_io][get_io_capa()];
} }
static int le_encrypt(const uint8_t key[16], const uint8_t plaintext[16],
uint8_t enc_data[16])
{
struct tc_aes_key_sched_struct s;
uint8_t tmp[16];
BT_DBG("key %s plaintext %s", bt_hex(key, 16), bt_hex(plaintext, 16));
sys_memcpy_swap(tmp, key, 16);
if (tc_aes128_set_encrypt_key(&s, tmp) == TC_CRYPTO_FAIL) {
return -EINVAL;
}
sys_memcpy_swap(tmp, plaintext, 16);
if (tc_aes_encrypt(enc_data, tmp, &s) == TC_CRYPTO_FAIL) {
return -EINVAL;
}
sys_mem_swap(enc_data, 16);
BT_DBG("enc_data %s", bt_hex(enc_data, 16));
return 0;
}
static struct net_buf *smp_create_pdu(struct bt_conn *conn, uint8_t op, static struct net_buf *smp_create_pdu(struct bt_conn *conn, uint8_t op,
size_t len) size_t len)
{ {
@ -338,7 +312,7 @@ static int smp_ah(const uint8_t irk[16], const uint8_t r[3], uint8_t out[3])
memcpy(res, r, 3); memcpy(res, r, 3);
memset(res + 3, 0, 13); memset(res + 3, 0, 13);
err = le_encrypt(irk, res, res); err = bt_encrypt(irk, res, res);
if (err) { if (err) {
return err; return err;
} }
@ -1578,7 +1552,7 @@ static int smp_c1(const uint8_t k[16], const uint8_t r[16],
/* Using enc_data as temporary output buffer */ /* Using enc_data as temporary output buffer */
xor_128(r, p1, enc_data); xor_128(r, p1, enc_data);
err = le_encrypt(k, enc_data, enc_data); err = bt_encrypt(k, enc_data, enc_data);
if (err) { if (err) {
return err; return err;
} }
@ -1592,7 +1566,7 @@ static int smp_c1(const uint8_t k[16], const uint8_t r[16],
xor_128(enc_data, p2, enc_data); xor_128(enc_data, p2, enc_data);
return le_encrypt(k, enc_data, enc_data); return bt_encrypt(k, enc_data, enc_data);
} }
#endif /* !CONFIG_BLUETOOTH_SMP_SC_ONLY */ #endif /* !CONFIG_BLUETOOTH_SMP_SC_ONLY */
@ -1823,7 +1797,7 @@ static int smp_s1(const uint8_t k[16], const uint8_t r1[16],
memcpy(out + 8, r1, 8); memcpy(out + 8, r1, 8);
/* s1(k, r1 , r2) = e(k, r') */ /* s1(k, r1 , r2) = e(k, r') */
return le_encrypt(k, out, out); return bt_encrypt(k, out, out);
} }
static uint8_t legacy_get_pair_method(struct bt_smp *smp, uint8_t remote_io) static uint8_t legacy_get_pair_method(struct bt_smp *smp, uint8_t remote_io)