bluetooth: controller: openisa: encryption and decryption using CAUv3
Created unit tests for the encryption and decryption functions. Tested with the peripheral and with central_hr samples. Due to latency of CAUv3 when used as CCM inline accelerator only one of the PDU can be encrypted/decrypted within an bilateral exchange M->S + S->M in a connection event. If the RXed PDU is encrypted, the TXed PDU must be empty with More Data if there is data in the LLL queue. The TXed PDU will be encrypted when an empty PDU is RXed. Signed-off-by: Cristi Caciuloiu <cristian.caciuloiu@nxp.com>
This commit is contained in:
parent
a9bfd28a39
commit
2a2f84256c
7 changed files with 417 additions and 30 deletions
|
@ -82,6 +82,15 @@ if BT
|
||||||
config BT_CTLR
|
config BT_CTLR
|
||||||
default y
|
default y
|
||||||
|
|
||||||
|
#TODO: Resolve the complete non-BLE support for crypto CAU3 firmware/driver
|
||||||
|
#config HAS_RV32M1_CAU3
|
||||||
|
# bool
|
||||||
|
# default y if BT_CTLR_CRYPTO && !BT_CTLR_LE_ENC_SUPPORT
|
||||||
|
|
||||||
|
config HAS_RV32M1_CAU3_BLE
|
||||||
|
bool
|
||||||
|
default y if BT_CTLR_CRYPTO && BT_CTLR_LE_ENC_SUPPORT
|
||||||
|
|
||||||
config RV32M1_INTMUX_CHANNEL_2
|
config RV32M1_INTMUX_CHANNEL_2
|
||||||
default n
|
default n
|
||||||
|
|
||||||
|
|
|
@ -142,6 +142,7 @@ with this board:
|
||||||
- peripheral_esp (Environmental Sensing Service)
|
- peripheral_esp (Environmental Sensing Service)
|
||||||
- peripheral_hr (Heart Rate)
|
- peripheral_hr (Heart Rate)
|
||||||
- peripheral_ht (Health Thermometer)
|
- peripheral_ht (Health Thermometer)
|
||||||
|
- peripheral
|
||||||
- scan_adv
|
- scan_adv
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
@ -150,8 +151,7 @@ with this board:
|
||||||
|
|
||||||
- **no 2 Mbps PHY**
|
- **no 2 Mbps PHY**
|
||||||
- no 512/256 Kbps PHY
|
- no 512/256 Kbps PHY
|
||||||
- **no controller-based cryptographic services (neither RPA nor LL encryption
|
- **no LL Privacy**
|
||||||
or decryption)**
|
|
||||||
- no mesh support
|
- no mesh support
|
||||||
- **no power-save**
|
- **no power-save**
|
||||||
- no TX power adjustment
|
- no TX power adjustment
|
||||||
|
|
|
@ -146,6 +146,7 @@ config BT_LLL_VENDOR_OPENISA
|
||||||
bool "Use OpenISA LLL"
|
bool "Use OpenISA LLL"
|
||||||
depends on BT_LL_SW_SPLIT && SOC_OPENISA_RV32M1_RISCV32
|
depends on BT_LL_SW_SPLIT && SOC_OPENISA_RV32M1_RISCV32
|
||||||
select BT_HAS_HCI_VS
|
select BT_HAS_HCI_VS
|
||||||
|
select BT_CTLR_LE_ENC_SUPPORT if !BT_CTLR_DATA_LENGTH_CLEAR
|
||||||
default y
|
default y
|
||||||
help
|
help
|
||||||
Use OpenISA Lower Link Layer implementation.
|
Use OpenISA Lower Link Layer implementation.
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2016-2017 Nordic Semiconductor ASA
|
* Copyright (c) 2016-2017 Nordic Semiconductor ASA
|
||||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||||
* Copyright 2019 NXP
|
* Copyright 2019-2020 NXP
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
@ -10,22 +10,96 @@
|
||||||
|
|
||||||
#include <sys/dlist.h>
|
#include <sys/dlist.h>
|
||||||
#include <sys/mempool_base.h>
|
#include <sys/mempool_base.h>
|
||||||
|
#include <sys/byteorder.h>
|
||||||
|
|
||||||
#include "util/mem.h"
|
|
||||||
#include "hal/ecb.h"
|
#include "hal/ecb.h"
|
||||||
|
|
||||||
#define LOG_MODULE_NAME bt_ctlr_rv32m1_ecb
|
#define LOG_MODULE_NAME bt_ctlr_rv32m1_ecb
|
||||||
#include "common/log.h"
|
#include "common/log.h"
|
||||||
#include "hal/debug.h"
|
#include "hal/debug.h"
|
||||||
|
#include "fsl_cau3_ble.h"
|
||||||
|
|
||||||
void ecb_encrypt_be(u8_t const *const key_be, u8_t const *const clear_text_be,
|
void ecb_encrypt_be(u8_t const *const key_be, u8_t const *const clear_text_be,
|
||||||
u8_t * const cipher_text_be)
|
u8_t *const cipher_text_be)
|
||||||
{
|
{
|
||||||
|
u8_t keyAes[16] __aligned(4);
|
||||||
|
status_t status;
|
||||||
|
|
||||||
|
cau3_handle_t handle;
|
||||||
|
|
||||||
|
memcpy(&keyAes, key_be, sizeof(keyAes));
|
||||||
|
|
||||||
|
/* CAU3 driver supports 4 key slots. */
|
||||||
|
handle.keySlot = kCAU3_KeySlot1;
|
||||||
|
|
||||||
|
/* After encrypt/decrypt req is sent to CAU3, the Host CPU will
|
||||||
|
* execute WFE() until CAU3 signals task done by setting the event.
|
||||||
|
*/
|
||||||
|
handle.taskDone = kCAU3_TaskDonePoll;
|
||||||
|
|
||||||
|
/* Loads the key into CAU3's DMEM and expands the AES key schedule */
|
||||||
|
status = CAU3_AES_SetKey(CAU3, &handle, keyAes, sizeof(keyAes));
|
||||||
|
if (status != kStatus_Success) {
|
||||||
|
LOG_ERR("CAUv3 AES key set failed %d", status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = CAU3_AES_Encrypt(CAU3, &handle, clear_text_be, cipher_text_be);
|
||||||
|
if (status != kStatus_Success) {
|
||||||
|
LOG_ERR("CAUv3 AES encrypt failed %d", status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ecb_encrypt(u8_t const *const key_le, u8_t const *const clear_text_le,
|
void ecb_encrypt(u8_t const *const key_le, u8_t const *const clear_text_le,
|
||||||
u8_t * const cipher_text_le, u8_t * const cipher_text_be)
|
u8_t *const cipher_text_le, u8_t *const cipher_text_be)
|
||||||
{
|
{
|
||||||
|
u8_t keyAes[16] __aligned(4);
|
||||||
|
u8_t clear[16];
|
||||||
|
u8_t cipher[16];
|
||||||
|
status_t status;
|
||||||
|
|
||||||
|
cau3_handle_t handle;
|
||||||
|
|
||||||
|
/* The security function e of the cryptographic toolbox in CAU as in STD
|
||||||
|
* The most significant octet of key corresponds to key[0], the most
|
||||||
|
* significant octet of plaintextData corresponds to in[0] and the most
|
||||||
|
* significant octet of encryptedData corresponds to out[0] using the
|
||||||
|
* notation specified in FIPS-197
|
||||||
|
* Thus, reverse the input parameters that are LSB to MSB format (le)
|
||||||
|
*/
|
||||||
|
sys_memcpy_swap(&keyAes, key_le, sizeof(keyAes));
|
||||||
|
sys_memcpy_swap(&clear, clear_text_le, sizeof(clear));
|
||||||
|
|
||||||
|
/* CAU3 driver supports 4 key slots. */
|
||||||
|
handle.keySlot = kCAU3_KeySlot1;
|
||||||
|
|
||||||
|
/* After encrypt/decrypt req is sent to CAU3, the Host CPU will
|
||||||
|
* execute WFE() until CAU3 signals task done by setting the event.
|
||||||
|
*/
|
||||||
|
handle.taskDone = kCAU3_TaskDonePoll;
|
||||||
|
|
||||||
|
/* Loads the key into CAU3's DMEM and expands the AES key schedule */
|
||||||
|
status = CAU3_AES_SetKey(CAU3, &handle, keyAes, sizeof(keyAes));
|
||||||
|
if (status != kStatus_Success) {
|
||||||
|
LOG_ERR("CAUv3 AES key set failed %d", status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = CAU3_AES_Encrypt(CAU3, &handle, clear, cipher);
|
||||||
|
if (status != kStatus_Success) {
|
||||||
|
LOG_ERR("CAUv3 AES encrypt failed %d", status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cipher_text_le) {
|
||||||
|
/* STD e function outputs in MSB thus reverse for the (le) */
|
||||||
|
sys_memcpy_swap(cipher_text_le, &cipher[0], sizeof(cipher));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cipher_text_be) {
|
||||||
|
memcpy(cipher_text_be, &cipher, sizeof(cipher));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u32_t ecb_encrypt_nonblocking(struct ecb *ecb)
|
u32_t ecb_encrypt_nonblocking(struct ecb *ecb)
|
||||||
|
@ -33,23 +107,63 @@ u32_t ecb_encrypt_nonblocking(struct ecb *ecb)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef RV32M1_ECB_IMPL
|
|
||||||
static void ecb_cleanup(void)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ecb_cb(u32_t status, u8_t *cipher_be, void *context)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* RV32M1_ECB_IMPL */
|
|
||||||
|
|
||||||
void isr_ecb(void *param)
|
void isr_ecb(void *param)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Used by ULL as in this example:
|
||||||
|
* ltk[16] is copied from the HCI packet, preserving the LSO to MSO format
|
||||||
|
* skd[16] is copied from the PDU, preserving the LSO to MSO format
|
||||||
|
* calc the Session Key and retrieve the MSO to LSO format because that is how
|
||||||
|
* the PDU payload uses the encrypted data; MIC is also MSO to LSO.
|
||||||
|
ecb_encrypt(&conn->llcp_enc.ltk[0],
|
||||||
|
&conn->llcp.encryption.skd[0], NULL,
|
||||||
|
&lll->ccm_rx.key[0]);
|
||||||
|
*/
|
||||||
u32_t ecb_ut(void)
|
u32_t ecb_ut(void)
|
||||||
{
|
{
|
||||||
return 0;
|
/*
|
||||||
|
* LTK = 0x4C68384139F574D836BCF34E9DFB01BF (MSO to LSO)
|
||||||
|
* SKD = SKDm || SKDs
|
||||||
|
* SKD (LSO to MSO)
|
||||||
|
* :0x13:0x02:0xF1:0xE0:0xDF:0xCE:0xBD:0xAC
|
||||||
|
* :0x79:0x68:0x57:0x46:0x35:0x24:0x13:0x02
|
||||||
|
* SK = Encrypt(LTK, SKD)
|
||||||
|
* SK (LSO to MSO)
|
||||||
|
* :0x66:0xC6:0xC2:0x27:0x8E:0x3B:0x8E:0x05
|
||||||
|
* :0x3E:0x7E:0xA3:0x26:0x52:0x1B:0xAD:0x99
|
||||||
|
*/
|
||||||
|
static const u8_t ltk_le[16] = {
|
||||||
|
0xbf, 0x01, 0xfb, 0x9d, 0x4e, 0xf3, 0xbc, 0x36,
|
||||||
|
0xd8, 0x74, 0xf5, 0x39, 0x41, 0x38, 0x68, 0x4c
|
||||||
|
};
|
||||||
|
static const u8_t skd_le[16] = {
|
||||||
|
0x13, 0x02, 0xF1, 0xE0, 0xDF, 0xCE, 0xBD, 0xAC,
|
||||||
|
0x79, 0x68, 0x57, 0x46, 0x35, 0x24, 0x13, 0x02
|
||||||
|
};
|
||||||
|
u8_t key_le[16] = {};
|
||||||
|
u8_t key_ref_le[16] = {
|
||||||
|
0x66, 0xC6, 0xC2, 0x27, 0x8E, 0x3B, 0x8E, 0x05,
|
||||||
|
0x3E, 0x7E, 0xA3, 0x26, 0x52, 0x1B, 0xAD, 0x99
|
||||||
|
};
|
||||||
|
u32_t status = kStatus_Success;
|
||||||
|
u8_t *key;
|
||||||
|
|
||||||
|
/* calc the Session Key and compare vs the ref_le in LSO format */
|
||||||
|
ecb_encrypt(ltk_le, skd_le, key = key_le, NULL);
|
||||||
|
|
||||||
|
if (memcmp(key_ref_le, key, 16)) {
|
||||||
|
printk("Failed session key unit test\n");
|
||||||
|
status = kStatus_Fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
printk("Session key: %02x %02x %02x %02x %02x %02x %02x %02x "
|
||||||
|
"%02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||||
|
key[0], key[1], key[2], key[3],
|
||||||
|
key[4], key[5], key[6], key[7],
|
||||||
|
key[8], key[9], key[10], key[11],
|
||||||
|
key[12], key[13], key[14], key[15]);
|
||||||
|
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2016 - 2019 Nordic Semiconductor ASA
|
* Copyright (c) 2016 - 2019 Nordic Semiconductor ASA
|
||||||
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
* Copyright (c) 2016 Vinayak Kariappa Chettimada
|
||||||
* Copyright 2019 NXP
|
* Copyright 2019 - 2020 NXP
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
@ -10,6 +10,7 @@
|
||||||
#include <sys/dlist.h>
|
#include <sys/dlist.h>
|
||||||
#include <sys/mempool_base.h>
|
#include <sys/mempool_base.h>
|
||||||
#include <toolchain.h>
|
#include <toolchain.h>
|
||||||
|
#include <irq.h>
|
||||||
|
|
||||||
#include "util/mem.h"
|
#include "util/mem.h"
|
||||||
#include "hal/ccm.h"
|
#include "hal/ccm.h"
|
||||||
|
@ -17,15 +18,21 @@
|
||||||
#include "ll_sw/pdu.h"
|
#include "ll_sw/pdu.h"
|
||||||
|
|
||||||
#include "fsl_xcvr.h"
|
#include "fsl_xcvr.h"
|
||||||
#include "irq.h"
|
|
||||||
#include "hal/cntr.h"
|
#include "hal/cntr.h"
|
||||||
#include "hal/ticker.h"
|
#include "hal/ticker.h"
|
||||||
#include "hal/swi.h"
|
#include "hal/swi.h"
|
||||||
|
#include "fsl_cau3_ble.h" /* must be after irq.h */
|
||||||
|
|
||||||
|
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_DRIVER)
|
||||||
|
#define LOG_MODULE_NAME bt_openisa_radio
|
||||||
|
#include "common/log.h"
|
||||||
|
#include <soc.h>
|
||||||
|
#include "hal/debug.h"
|
||||||
|
|
||||||
static radio_isr_cb_t isr_cb;
|
static radio_isr_cb_t isr_cb;
|
||||||
static void *isr_cb_param;
|
static void *isr_cb_param;
|
||||||
|
|
||||||
|
#define RADIO_AESCCM_HDR_MASK 0xE3 /* AES-CCM: NESN, SN, MD bits masked to 0 */
|
||||||
#define RADIO_PDU_LEN_MAX (BIT(8) - 1)
|
#define RADIO_PDU_LEN_MAX (BIT(8) - 1)
|
||||||
|
|
||||||
/* us values */
|
/* us values */
|
||||||
|
@ -77,6 +84,16 @@ static u8_t MALIGN(4) _pkt_scratch[
|
||||||
|
|
||||||
static s8_t rssi;
|
static s8_t rssi;
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
union {
|
||||||
|
u64_t counter;
|
||||||
|
u8_t bytes[CAU3_AES_BLOCK_SIZE - 1 - 2];
|
||||||
|
} nonce; /* used by the B0 format but not in-situ */
|
||||||
|
struct pdu_data *rx_pkt_out;
|
||||||
|
struct pdu_data *rx_pkt_in;
|
||||||
|
u8_t auth_mic_valid;
|
||||||
|
u8_t empty_pdu_rxed;
|
||||||
|
} ctx_ccm;
|
||||||
|
|
||||||
static void tmp_cb(void *param)
|
static void tmp_cb(void *param)
|
||||||
{
|
{
|
||||||
|
@ -150,6 +167,15 @@ static void pkt_rx(void)
|
||||||
while (*sts & GENFSK_XCVR_STS_RX_IN_PROGRESS_MASK) {
|
while (*sts & GENFSK_XCVR_STS_RX_IN_PROGRESS_MASK) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ctx_ccm.rx_pkt_out) {
|
||||||
|
*(u16_t *)ctx_ccm.rx_pkt_out = pb[0];
|
||||||
|
if (len < CAU3_BLE_MIC_SIZE) {
|
||||||
|
ctx_ccm.rx_pkt_out = 0;
|
||||||
|
ctx_ccm.rx_pkt_in = 0;
|
||||||
|
ctx_ccm.empty_pdu_rxed = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Copy the PDU */
|
/* Copy the PDU */
|
||||||
for (idx = 0; idx < len / 2; idx++) {
|
for (idx = 0; idx < len / 2; idx++) {
|
||||||
rxb[idx] = pb[idx];
|
rxb[idx] = pb[idx];
|
||||||
|
@ -318,6 +344,12 @@ static void hpmcal_disable(void)
|
||||||
|
|
||||||
void radio_setup(void)
|
void radio_setup(void)
|
||||||
{
|
{
|
||||||
|
XCVR_Reset();
|
||||||
|
|
||||||
|
#if defined(CONFIG_BT_CTLR_PRIVACY) || defined(CONFIG_BT_CTLR_LE_ENC)
|
||||||
|
CAU3_Init(CAU3);
|
||||||
|
#endif /* CONFIG_BT_CTLR_PRIVACY || CONFIG_BT_CTLR_LE_ENC */
|
||||||
|
|
||||||
XCVR_Init(GFSK_BT_0p5_h_0p5, DR_1MBPS);
|
XCVR_Init(GFSK_BT_0p5_h_0p5, DR_1MBPS);
|
||||||
XCVR_SetXtalTrim(41);
|
XCVR_SetXtalTrim(41);
|
||||||
|
|
||||||
|
@ -955,28 +987,250 @@ u32_t radio_tmr_sample_get(void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *radio_ccm_rx_pkt_set_ut(struct ccm *ccm, u8_t phy, void *pkt)
|
||||||
|
{
|
||||||
|
/* Saved by LL as MSO to LSO in the ccm->key
|
||||||
|
* SK (LSO to MSO)
|
||||||
|
* :0x66:0xC6:0xC2:0x27:0x8E:0x3B:0x8E:0x05
|
||||||
|
* :0x3E:0x7E:0xA3:0x26:0x52:0x1B:0xAD:0x99
|
||||||
|
*/
|
||||||
|
u8_t key_local[16] __aligned(4) = {
|
||||||
|
0x99, 0xad, 0x1b, 0x52, 0x26, 0xa3, 0x7e, 0x3e,
|
||||||
|
0x05, 0x8e, 0x3b, 0x8e, 0x27, 0xc2, 0xc6, 0x66
|
||||||
|
};
|
||||||
|
void *result;
|
||||||
|
|
||||||
|
/* ccm.key[16] is stored in MSO format, as retrieved from e function */
|
||||||
|
memcpy(ccm->key, key_local, sizeof(key_local));
|
||||||
|
|
||||||
|
/* Input std sample data, vol 6, part C, ch 1 */
|
||||||
|
_pkt_scratch[0] = 0x0f;
|
||||||
|
_pkt_scratch[1] = 0x05;
|
||||||
|
_pkt_scratch[2] = 0x9f; /* cleartext = 0x06*/
|
||||||
|
_pkt_scratch[3] = 0xcd;
|
||||||
|
_pkt_scratch[4] = 0xa7;
|
||||||
|
_pkt_scratch[5] = 0xf4;
|
||||||
|
_pkt_scratch[6] = 0x48;
|
||||||
|
|
||||||
|
/* IV std sample data, vol 6, part C, ch 1, stored in LL in LSO format
|
||||||
|
* IV (LSO to MSO) :0x24:0xAB:0xDC:0xBA:0xBE:0xBA:0xAF:0xDE
|
||||||
|
*/
|
||||||
|
ccm->iv[0] = 0x24;
|
||||||
|
ccm->iv[1] = 0xAB;
|
||||||
|
ccm->iv[2] = 0xDC;
|
||||||
|
ccm->iv[3] = 0xBA;
|
||||||
|
ccm->iv[4] = 0xBE;
|
||||||
|
ccm->iv[5] = 0xBA;
|
||||||
|
ccm->iv[6] = 0xAF;
|
||||||
|
ccm->iv[7] = 0xDE;
|
||||||
|
|
||||||
|
result = radio_ccm_rx_pkt_set(ccm, phy, pkt);
|
||||||
|
radio_ccm_is_done();
|
||||||
|
|
||||||
|
if (ctx_ccm.auth_mic_valid == 1 && ((u8_t *)pkt)[2] == 0x06) {
|
||||||
|
BT_INFO("Passed decrypt\n");
|
||||||
|
} else {
|
||||||
|
BT_INFO("Failed decrypt\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void *radio_ccm_rx_pkt_set(struct ccm *ccm, u8_t phy, void *pkt)
|
void *radio_ccm_rx_pkt_set(struct ccm *ccm, u8_t phy, void *pkt)
|
||||||
{
|
{
|
||||||
printk("%s\n", __func__);
|
u8_t key_local[16] __aligned(4);
|
||||||
return NULL;
|
status_t status;
|
||||||
|
cau3_handle_t handle = {
|
||||||
|
.keySlot = kCAU3_KeySlot2,
|
||||||
|
.taskDone = kCAU3_TaskDonePoll
|
||||||
|
};
|
||||||
|
ARG_UNUSED(phy);
|
||||||
|
|
||||||
|
/* ccm.key[16] is stored in MSO format, as retrieved from e function */
|
||||||
|
memcpy(key_local, ccm->key, sizeof(key_local));
|
||||||
|
ctx_ccm.auth_mic_valid = 0;
|
||||||
|
ctx_ccm.empty_pdu_rxed = 0;
|
||||||
|
ctx_ccm.rx_pkt_in = (struct pdu_data *)_pkt_scratch;
|
||||||
|
ctx_ccm.rx_pkt_out = (struct pdu_data *)pkt;
|
||||||
|
ctx_ccm.nonce.counter = ccm->counter; /* LSO to MSO, counter is LE */
|
||||||
|
/* The directionBit set to 1 for Data Physical Chan PDUs sent by
|
||||||
|
* the master and set to 0 for Data Physical Chan PDUs sent by the slave
|
||||||
|
*/
|
||||||
|
ctx_ccm.nonce.bytes[4] |= ccm->direction << 7;
|
||||||
|
memcpy(&ctx_ccm.nonce.bytes[5], ccm->iv, 8); /* LSO to MSO */
|
||||||
|
|
||||||
|
/* Loads the key into CAU3's DMEM and expands the AES key schedule. */
|
||||||
|
status = CAU3_AES_SetKey(CAU3, &handle, key_local, 16);
|
||||||
|
if (status != kStatus_Success) {
|
||||||
|
BT_ERR("CAUv3 AES key set failed %d", status);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _pkt_scratch;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *radio_ccm_tx_pkt_set_ut(struct ccm *ccm, void *pkt)
|
||||||
|
{
|
||||||
|
/* Clear:
|
||||||
|
* 06 1b 17 00 37 36 35 34 33 32 31 30 41 42 43
|
||||||
|
* 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51
|
||||||
|
*/
|
||||||
|
u8_t data_in[29] = {
|
||||||
|
0x06, 0x1b, 0x17, 0x00, 0x37, 0x36, 0x35, 0x34,
|
||||||
|
0x33, 0x32, 0x31, 0x30, 0x41, 0x42, 0x43, 0x44,
|
||||||
|
0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c,
|
||||||
|
0x4d, 0x4e, 0x4f, 0x50, 0x51
|
||||||
|
};
|
||||||
|
/* LL_DATA2:
|
||||||
|
* 06 1f f3 88 81 e7 bd 94 c9 c3 69 b9 a6 68 46
|
||||||
|
* dd 47 86 aa 8c 39 ce 54 0d 0d ae 3a dc df 89 b9 60 88
|
||||||
|
*/
|
||||||
|
u8_t data_ref_out[33] = {
|
||||||
|
0x06, 0x1f, 0xf3, 0x88, 0x81, 0xe7, 0xbd, 0x94,
|
||||||
|
0xc9, 0xc3, 0x69, 0xb9, 0xa6, 0x68, 0x46, 0xdd,
|
||||||
|
0x47, 0x86, 0xaa, 0x8c, 0x39, 0xce, 0x54, 0x0d,
|
||||||
|
0x0d, 0xae, 0x3a, 0xdc, 0xdf,
|
||||||
|
0x89, 0xb9, 0x60, 0x88
|
||||||
|
};
|
||||||
|
/* Saved by LL as MSO to LSO in the ccm->key
|
||||||
|
* SK (LSO to MSO)
|
||||||
|
* :0x66:0xC6:0xC2:0x27:0x8E:0x3B:0x8E:0x05
|
||||||
|
* :0x3E:0x7E:0xA3:0x26:0x52:0x1B:0xAD:0x99
|
||||||
|
*/
|
||||||
|
u8_t key_local[16] __aligned(4) = {
|
||||||
|
0x99, 0xad, 0x1b, 0x52, 0x26, 0xa3, 0x7e, 0x3e,
|
||||||
|
0x05, 0x8e, 0x3b, 0x8e, 0x27, 0xc2, 0xc6, 0x66
|
||||||
|
};
|
||||||
|
void *result;
|
||||||
|
|
||||||
|
/* ccm.key[16] is stored in MSO format, as retrieved from e function */
|
||||||
|
memcpy(ccm->key, key_local, sizeof(key_local));
|
||||||
|
memcpy(pkt, data_in, sizeof(data_in));
|
||||||
|
/* IV std sample data, vol 6, part C, ch 1, stored in LL in LSO format
|
||||||
|
* IV (LSO to MSO) :0x24:0xAB:0xDC:0xBA:0xBE:0xBA:0xAF:0xDE
|
||||||
|
*/
|
||||||
|
ccm->iv[0] = 0x24;
|
||||||
|
ccm->iv[1] = 0xAB;
|
||||||
|
ccm->iv[2] = 0xDC;
|
||||||
|
ccm->iv[3] = 0xBA;
|
||||||
|
ccm->iv[4] = 0xBE;
|
||||||
|
ccm->iv[5] = 0xBA;
|
||||||
|
ccm->iv[6] = 0xAF;
|
||||||
|
ccm->iv[7] = 0xDE;
|
||||||
|
/* 4. Data packet2 (packet 1, S --> M) */
|
||||||
|
ccm->counter = 1;
|
||||||
|
ccm->direction = 0;
|
||||||
|
|
||||||
|
result = radio_ccm_tx_pkt_set(ccm, pkt);
|
||||||
|
|
||||||
|
if (memcmp(result, data_ref_out, sizeof(data_ref_out))) {
|
||||||
|
BT_INFO("Failed encrypt\n");
|
||||||
|
} else {
|
||||||
|
BT_INFO("Passed encrypt\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *radio_ccm_tx_pkt_set(struct ccm *ccm, void *pkt)
|
void *radio_ccm_tx_pkt_set(struct ccm *ccm, void *pkt)
|
||||||
{
|
{
|
||||||
printk("%s\n", __func__);
|
u8_t key_local[16] __aligned(4);
|
||||||
return NULL;
|
u8_t aad;
|
||||||
|
u8_t *auth_mic;
|
||||||
|
status_t status;
|
||||||
|
cau3_handle_t handle = {
|
||||||
|
.keySlot = kCAU3_KeySlot2,
|
||||||
|
.taskDone = kCAU3_TaskDonePoll
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Test for Empty PDU and bypass encryption */
|
||||||
|
if (((struct pdu_data *)pkt)->len == 0) {
|
||||||
|
return pkt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ccm.key[16] is stored in MSO format, as retrieved from e function */
|
||||||
|
memcpy(key_local, ccm->key, sizeof(key_local));
|
||||||
|
ctx_ccm.nonce.counter = ccm->counter; /* LSO to MSO, counter is LE */
|
||||||
|
/* The directionBit set to 1 for Data Physical Chan PDUs sent by
|
||||||
|
* the master and set to 0 for Data Physical Chan PDUs sent by the slave
|
||||||
|
*/
|
||||||
|
ctx_ccm.nonce.bytes[4] |= ccm->direction << 7;
|
||||||
|
memcpy(&ctx_ccm.nonce.bytes[5], ccm->iv, 8); /* LSO to MSO */
|
||||||
|
|
||||||
|
/* Loads the key into CAU3's DMEM and expands the AES key schedule. */
|
||||||
|
status = CAU3_AES_SetKey(CAU3, &handle, key_local, 16);
|
||||||
|
if (status != kStatus_Success) {
|
||||||
|
BT_ERR("CAUv3 AES key set failed %d", status);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
auth_mic = _pkt_scratch + 2 + ((struct pdu_data *)pkt)->len;
|
||||||
|
aad = *(u8_t *)pkt & RADIO_AESCCM_HDR_MASK;
|
||||||
|
|
||||||
|
status = CAU3_AES_CCM_EncryptTag(CAU3, &handle,
|
||||||
|
(u8_t *)pkt + 2, ((struct pdu_data *)pkt)->len,
|
||||||
|
_pkt_scratch + 2,
|
||||||
|
ctx_ccm.nonce.bytes, 13,
|
||||||
|
&aad, 1, auth_mic, CAU3_BLE_MIC_SIZE);
|
||||||
|
if (status != kStatus_Success) {
|
||||||
|
BT_ERR("CAUv3 AES CCM decrypt failed %d", status);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_pkt_scratch[0] = *(u8_t *)pkt;
|
||||||
|
_pkt_scratch[1] = ((struct pdu_data *)pkt)->len + CAU3_BLE_MIC_SIZE;
|
||||||
|
|
||||||
|
return _pkt_scratch;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32_t radio_ccm_is_done(void)
|
u32_t radio_ccm_is_done(void)
|
||||||
{
|
{
|
||||||
printk("%s\n", __func__);
|
status_t status;
|
||||||
return 0;
|
u8_t *auth_mic;
|
||||||
|
u8_t aad;
|
||||||
|
cau3_handle_t handle = {
|
||||||
|
.keySlot = kCAU3_KeySlot2,
|
||||||
|
.taskDone = kCAU3_TaskDonePoll
|
||||||
|
};
|
||||||
|
|
||||||
|
if (ctx_ccm.rx_pkt_in->len > CAU3_BLE_MIC_SIZE) {
|
||||||
|
auth_mic = (u8_t *)ctx_ccm.rx_pkt_in + 2 +
|
||||||
|
ctx_ccm.rx_pkt_in->len - CAU3_BLE_MIC_SIZE;
|
||||||
|
aad = *(u8_t *)ctx_ccm.rx_pkt_in & RADIO_AESCCM_HDR_MASK;
|
||||||
|
status = CAU3_AES_CCM_DecryptTag(CAU3, &handle,
|
||||||
|
(u8_t *)ctx_ccm.rx_pkt_in + 2,
|
||||||
|
(u8_t *)ctx_ccm.rx_pkt_out + 2,
|
||||||
|
ctx_ccm.rx_pkt_in->len - CAU3_BLE_MIC_SIZE,
|
||||||
|
ctx_ccm.nonce.bytes, 13,
|
||||||
|
&aad, 1, auth_mic, CAU3_BLE_MIC_SIZE);
|
||||||
|
if (status != kStatus_Success) {
|
||||||
|
BT_ERR("CAUv3 AES CCM decrypt failed %d", status);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx_ccm.auth_mic_valid = handle.micPassed;
|
||||||
|
ctx_ccm.rx_pkt_out->len -= 4;
|
||||||
|
|
||||||
|
} else if (ctx_ccm.rx_pkt_in->len == 0) {
|
||||||
|
/* Just copy input into output */
|
||||||
|
*ctx_ccm.rx_pkt_out = *ctx_ccm.rx_pkt_in;
|
||||||
|
ctx_ccm.auth_mic_valid = 1;
|
||||||
|
ctx_ccm.empty_pdu_rxed = 1;
|
||||||
|
} else {
|
||||||
|
return 0; /* length only allowed 0, not 1,2,3,4 */
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32_t radio_ccm_mic_is_valid(void)
|
u32_t radio_ccm_mic_is_valid(void)
|
||||||
{
|
{
|
||||||
printk("%s\n", __func__);
|
return ctx_ccm.auth_mic_valid;
|
||||||
return 0;
|
}
|
||||||
|
|
||||||
|
u32_t radio_ccm_is_available(void)
|
||||||
|
{
|
||||||
|
return ctx_ccm.empty_pdu_rxed;
|
||||||
}
|
}
|
||||||
|
|
||||||
void radio_ar_configure(u32_t nirk, void *irk)
|
void radio_ar_configure(u32_t nirk, void *irk)
|
||||||
|
|
|
@ -96,6 +96,7 @@ void *radio_ccm_rx_pkt_set(struct ccm *ccm, u8_t phy, void *pkt);
|
||||||
void *radio_ccm_tx_pkt_set(struct ccm *ccm, void *pkt);
|
void *radio_ccm_tx_pkt_set(struct ccm *ccm, void *pkt);
|
||||||
u32_t radio_ccm_is_done(void);
|
u32_t radio_ccm_is_done(void);
|
||||||
u32_t radio_ccm_mic_is_valid(void);
|
u32_t radio_ccm_mic_is_valid(void);
|
||||||
|
u32_t radio_ccm_is_available(void);
|
||||||
|
|
||||||
void radio_ar_configure(u32_t nirk, void *irk);
|
void radio_ar_configure(u32_t nirk, void *irk);
|
||||||
u32_t radio_ar_match_get(void);
|
u32_t radio_ar_match_get(void);
|
||||||
|
|
|
@ -512,7 +512,15 @@ void lll_conn_pdu_tx_prep(struct lll_conn *lll, struct pdu_data **pdu_data_tx)
|
||||||
struct pdu_data *p;
|
struct pdu_data *p;
|
||||||
memq_link_t *link;
|
memq_link_t *link;
|
||||||
|
|
||||||
if (lll->empty) {
|
if (lll->empty
|
||||||
|
#if defined(CONFIG_BT_CTLR_LE_ENC)
|
||||||
|
|| (lll->enc_tx && !radio_ccm_is_available())
|
||||||
|
/* TODO: If CAUv3 is already used by the RX decrypt,
|
||||||
|
* there is no time to use it for TX if the link
|
||||||
|
* needs it, thus stall and send an empty packet w/ MD.
|
||||||
|
*/
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
*pdu_data_tx = empty_tx_enqueue(lll);
|
*pdu_data_tx = empty_tx_enqueue(lll);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue