Merge branch 'feat/support_bluedroid_host_smp_with_psa_tinycrypt' into 'master'

Supported bluedroid host smp with mbedtls and TinyCrypt

Closes BLERP-2468 and BLERP-2490

See merge request espressif/esp-idf!44575
This commit is contained in:
Zhi Wei Jian
2025-12-31 11:36:28 +08:00
15 changed files with 693 additions and 52 deletions
+6 -1
View File
@@ -729,7 +729,12 @@ if(CONFIG_BT_ENABLED)
)
endif()
if(NOT (CONFIG_BT_LE_CRYPTO_STACK_MBEDTLS OR CONFIG_BT_NIMBLE_CRYPTO_STACK_MBEDTLS))
# Compile TinyCrypt if:
# 1. Controller uses TinyCrypt (not mbedTLS), OR
# 2. NimBLE uses TinyCrypt (not mbedTLS), OR
# 3. Bluedroid Host SMP uses TinyCrypt
if(CONFIG_BT_SMP_CRYPTO_STACK_TINYCRYPT OR
(NOT CONFIG_BT_LE_CRYPTO_STACK_MBEDTLS AND NOT CONFIG_BT_NIMBLE_CRYPTO_STACK_MBEDTLS))
list(APPEND include_dirs
common/tinycrypt/include
common/tinycrypt/port
+37
View File
@@ -6,6 +6,43 @@ config BT_ALARM_MAX_NUM
This option decides the maximum number of alarms which
could be used by Bluetooth host.
choice BT_SMP_CRYPTO_STACK
prompt "SMP cryptographic stack"
depends on (BT_BLE_SMP_ENABLE || BT_SMP_ENABLE || BT_NIMBLE_SECURITY_ENABLE)
default BT_SMP_CRYPTO_STACK_NATIVE
help
Select the cryptographic library to use for SMP operations (AES, AES-CMAC, ECDH P-256).
config BT_SMP_CRYPTO_STACK_NATIVE
bool "Native Bluedroid implementation"
depends on (BT_BLE_SMP_ENABLE || BT_SMP_ENABLE)
help
Use the built-in Bluedroid cryptographic implementation.
This provides compatibility with all features.
This option is only available for Bluedroid host.
config BT_SMP_CRYPTO_STACK_TINYCRYPT
bool "TinyCrypt"
help
Use TinyCrypt library for cryptographic operations.
TinyCrypt is a lightweight cryptographic library designed for constrained devices.
This can reduce code size compared to the native implementation.
This is the default option.
config BT_SMP_CRYPTO_STACK_MBEDTLS
bool "mbedTLS"
select MBEDTLS_AES_C
select MBEDTLS_CMAC_C
select MBEDTLS_ECDH_C
select MBEDTLS_ECP_C
select MBEDTLS_ECP_DP_SECP256R1_ENABLED
help
Use mbedTLS library for cryptographic operations.
This can provide hardware acceleration on supported platforms and reduce code size
by sharing crypto implementations with other components.
endchoice
menu "BLE Log"
source "$IDF_PATH/components/bt/common/ble_log/Kconfig.in"
endmenu
@@ -473,6 +473,24 @@
#define UC_BT_BLE_SMP_BOND_NVS_FLASH FALSE
#endif
#ifdef CONFIG_BT_SMP_CRYPTO_STACK_NATIVE
#define UC_BT_SMP_CRYPTO_STACK_NATIVE TRUE
#else
#define UC_BT_SMP_CRYPTO_STACK_NATIVE FALSE
#endif
#ifdef CONFIG_BT_SMP_CRYPTO_STACK_MBEDTLS
#define UC_BT_SMP_CRYPTO_MBEDTLS TRUE
#else
#define UC_BT_SMP_CRYPTO_MBEDTLS FALSE
#endif
#ifdef CONFIG_BT_SMP_CRYPTO_STACK_TINYCRYPT
#define UC_BT_SMP_CRYPTO_TINYCRYPT TRUE
#else
#define UC_BT_SMP_CRYPTO_TINYCRYPT FALSE
#endif
//Device Name Maximum Length
#ifdef CONFIG_BT_MAX_DEVICE_NAME_LEN
#define UC_MAX_LOC_BD_NAME_LEN CONFIG_BT_MAX_DEVICE_NAME_LEN
@@ -523,6 +523,24 @@
#define BLE_SMP_BOND_NVS_FLASH FALSE
#endif
#if (UC_BT_SMP_CRYPTO_STACK_NATIVE)
#define SMP_CRYPTO_STACK_NATIVE TRUE
#else
#define SMP_CRYPTO_STACK_NATIVE FALSE
#endif /* UC_BT_SMP_CRYPTO_STACK_NATIVE */
#if (UC_BT_SMP_CRYPTO_MBEDTLS)
#define SMP_CRYPTO_MBEDTLS TRUE
#else
#define SMP_CRYPTO_MBEDTLS FALSE
#endif /* UC_BT_SMP_CRYPTO_MBEDTLS */
#if (UC_BT_SMP_CRYPTO_TINYCRYPT)
#define SMP_CRYPTO_TINYCRYPT TRUE
#else
#define SMP_CRYPTO_TINYCRYPT FALSE
#endif /* UC_BT_SMP_CRYPTO_TINYCRYPT */
#ifdef UC_BTDM_BLE_ADV_REPORT_FLOW_CTRL_SUPP
#define BLE_ADV_REPORT_FLOW_CONTROL (UC_BTDM_BLE_ADV_REPORT_FLOW_CTRL_SUPP && BLE_INCLUDED)
#endif /* UC_BTDM_BLE_ADV_REPORT_FLOW_CTRL_SUPP */
+5 -1
View File
@@ -48,6 +48,8 @@
/* add the target configuration to allow using internal data types and compilation options */
#include "common/bt_target.h"
#if (SMP_CRYPTO_STACK_NATIVE == TRUE)
/* define if you have fast 32-bit types on your system */
#if 1
# define HAVE_UINT_32T
@@ -569,7 +571,7 @@ return_type aes_set_key( const unsigned char key[], length_type keylen, aes_cont
/* Encrypt a single block of 16 bytes */
/* @breif change the name by snake for avoid the conflict with libcrypto */
/* @brief change the name by snake for avoid the conflict with libcrypto */
return_type bluedroid_aes_encrypt( const unsigned char in[N_BLOCK], unsigned char out[N_BLOCK], const aes_context ctx[1] )
{
if ( ctx->rnd ) {
@@ -935,4 +937,6 @@ void bluedroid_aes_decrypt_256( const unsigned char in[N_BLOCK], unsigned char o
copy_and_key( out, s1, o_key );
}
#endif /* SMP_CRYPTO_STACK_NATIVE == TRUE */
#endif
@@ -31,6 +31,10 @@
#ifndef AES_H
#define AES_H
#include "common/bt_target.h"
#if (SMP_CRYPTO_STACK_NATIVE == TRUE)
#if 1
# define AES_ENC_PREKEYED /* AES encryption with a precomputed key schedule */
#endif
@@ -117,7 +121,7 @@ return_type aes_cbc_decrypt( const unsigned char *in,
The encryption subroutines take a key in an array of bytes in
key[L] where L is 16, 24 or 32 bytes for key lengths of 128,
192, and 256 bits respectively. They then encrypts the input
data, in[] with this key and put the reult in the output array
data, in[] with this key and put the result in the output array
out[]. In addition, the second key array, o_key[L], is used
to output the key that is needed by the decryption subroutine
to reverse the encryption operation. The two key arrays can
@@ -159,4 +163,6 @@ void bluedroid_aes_decrypt_256( const unsigned char in[N_BLOCK],
unsigned char o_key[2 * N_BLOCK] );
#endif
#endif
#endif /* SMP_CRYPTO_STACK_NATIVE == TRUE */
#endif /* AES_H */
@@ -24,9 +24,12 @@
#pragma once
#include "p_256_multprecision.h"
#include "common/bt_target.h"
#if (SMP_CRYPTO_STACK_NATIVE == TRUE)
#include "p_256_multprecision.h"
typedef unsigned long DWORD;
typedef struct {
@@ -72,3 +75,5 @@ bool ECC_CheckPointIsInElliCur_P256(Point *p);
#define ECC_PointMult(q, p, n, keyLength) ECC_PointMult_Bin_NAF(q, p, n, keyLength)
void p_256_init_curve(UINT32 keyLength);
#endif /* SMP_CRYPTO_STACK_NATIVE == TRUE */
@@ -24,6 +24,9 @@
#pragma once
#include "stack/bt_types.h"
#include "common/bt_target.h"
#if (SMP_CRYPTO_STACK_NATIVE == TRUE)
/* Type definitions */
typedef unsigned long DWORD;
@@ -58,3 +61,5 @@ DWORD multiprecision_lshift(DWORD *c, DWORD *a, uint32_t keyLength);
void multiprecision_mult(DWORD *c, DWORD *a, DWORD *b, uint32_t keyLength);
void multiprecision_fast_mod(DWORD *c, DWORD *a);
void multiprecision_fast_mod_P256(DWORD *c, DWORD *a);
#endif /* SMP_CRYPTO_STACK_NATIVE == TRUE */
@@ -23,6 +23,10 @@
******************************************************************************/
#include <string.h>
#include "common/bt_target.h"
#if (SMP_CRYPTO_STACK_NATIVE == TRUE)
#include "p_256_ecc_pp.h"
void p_256_init_curve(UINT32 keyLength)
@@ -76,3 +80,5 @@ void p_256_init_curve(UINT32 keyLength)
ec->G.y[0] = 0x37bf51f5;
}
}
#endif /* SMP_CRYPTO_STACK_NATIVE == TRUE */
@@ -24,9 +24,12 @@
//#include <stdio.h>
//#include <stdlib.h>
#include <string.h>
#include "common/bt_target.h"
#if (SMP_CRYPTO_STACK_NATIVE == TRUE)
#include "p_256_ecc_pp.h"
#include "p_256_multprecision.h"
#include "common/bt_target.h"
#if SMP_DYNAMIC_MEMORY == FALSE
elliptic_curve_t curve;
@@ -281,3 +284,5 @@ bool ECC_CheckPointIsInElliCur_P256(Point *p)
return true;
}
}
#endif /* SMP_CRYPTO_STACK_NATIVE == TRUE */
@@ -24,6 +24,9 @@
#include <string.h>
#include "common/bt_target.h"
#if (SMP_CRYPTO_STACK_NATIVE == TRUE)
#include "p_256_ecc_pp.h"
#include "p_256_multprecision.h"
@@ -365,7 +368,7 @@ void multiprecision_fast_mod_P256(DWORD *c, DWORD *a)
uint8_t UB;
uint8_t UC;
uint8_t UD;
uint8_t UE;
uint8_t U_E;
uint8_t UF;
uint8_t UG;
DWORD U;
@@ -381,7 +384,7 @@ void multiprecision_fast_mod_P256(DWORD *c, DWORD *a)
// E = a[8] + a[9];
E = a[8];
E += a[9];
UE = (E < a[9]);
U_E = (E < a[9]);
// F = a[9] + a[10];
F = a[9];
@@ -418,7 +421,7 @@ void multiprecision_fast_mod_P256(DWORD *c, DWORD *a)
c[0] = a[0];
c[0] += E;
U = (c[0] < E);
U += UE;
U += U_E;
U -= (c[0] < A);
U -= UA;
c[0] -= A;
@@ -479,7 +482,7 @@ void multiprecision_fast_mod_P256(DWORD *c, DWORD *a)
U -= (c[3] < a[15]);
c[3] -= a[15];
U -= (c[3] < E);
U -= UE;
U -= U_E;
c[3] -= E;
if (U & 0x80000000) {
@@ -546,7 +549,7 @@ void multiprecision_fast_mod_P256(DWORD *c, DWORD *a)
c[6] += a[15];
U += (c[6] < a[15]);
U -= (c[6] < E);
U -= UE;
U -= U_E;
c[6] -= E;
if (U & 0x80000000) {
@@ -645,3 +648,5 @@ void multiprecision_inv_mod(DWORD *aminus, DWORD *u, uint32_t keyLength)
multiprecision_copy(aminus, C, keyLength);
}
}
#endif /* SMP_CRYPTO_STACK_NATIVE == TRUE */
@@ -22,7 +22,15 @@
#include "btm_int.h"
#include "stack/l2c_api.h"
#include "smp_int.h"
#if (SMP_CRYPTO_MBEDTLS == TRUE)
#include "psa/crypto.h"
#elif (SMP_CRYPTO_TINYCRYPT == TRUE)
#include "tinycrypt/ecc_dh.h"
#include "tinycrypt/ecc.h"
#include "tinycrypt/constants.h"
#else
#include "p_256_ecc_pp.h"
#endif
//#include "utils/include/bt_utils.h"
#if SMP_INCLUDED == TRUE
@@ -771,10 +779,78 @@ void smp_process_pairing_public_key(tSMP_CB *p_cb, tSMP_INT_DATA *p_data)
}
/* In order to prevent the x and y coordinates of the public key from being modified,
we need to check whether the x and y coordinates are on the given elliptic curve. */
#if (SMP_CRYPTO_MBEDTLS == TRUE)
{
/*
* PSA Crypto validates the public key when importing.
* We try to import the peer's public key as a ECC public key.
* If import fails, the key is invalid.
*/
psa_status_t status;
psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_key_id_t key_id = 0;
UINT8 pub_be[BT_OCTET32_LEN + BT_OCTET32_LEN + 1]; /* 0x04 || X (32 bytes) || Y (32 bytes) */
/* Construct peer public key in uncompressed format (0x04 || X || Y) */
pub_be[0] = 0x04;
for (int i = 0; i < BT_OCTET32_LEN; i++) {
pub_be[1 + i] = p_cb->peer_publ_key.x[BT_OCTET32_LEN - 1 - i];
pub_be[33 + i] = p_cb->peer_publ_key.y[BT_OCTET32_LEN - 1 - i];
}
/* Try to import as public key - PSA will validate it's on the curve */
psa_set_key_type(&key_attributes, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1));
psa_set_key_bits(&key_attributes, 256);
psa_set_key_usage_flags(&key_attributes, 0); /* No usage needed, just validating */
status = psa_import_key(&key_attributes, pub_be, sizeof(pub_be), &key_id);
psa_reset_key_attributes(&key_attributes);
if (status != PSA_SUCCESS) {
SMP_TRACE_ERROR("%s, Invalid Public key. psa_import_key failed: %d\n", __func__, status);
reason = SMP_INVALID_PARAMETERS;
smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
return;
}
/* Key is valid, clean up */
psa_destroy_key(key_id);
}
#elif (SMP_CRYPTO_TINYCRYPT == TRUE)
{
/*
* TinyCrypt validates the public key using uECC_valid_public_key.
* TinyCrypt expects public key in format: X (32 bytes) || Y (32 bytes), no prefix.
*/
UINT8 pub_be[64]; /* TinyCrypt format: X (32 bytes) || Y (32 bytes), no prefix */
/* Convert peer public key from little-endian to big-endian */
/* TinyCrypt format: X (32 bytes) || Y (32 bytes), no prefix */
for (int i = 0; i < BT_OCTET32_LEN; i++) {
pub_be[i] = p_cb->peer_publ_key.x[BT_OCTET32_LEN - 1 - i];
pub_be[BT_OCTET32_LEN + i] = p_cb->peer_publ_key.y[BT_OCTET32_LEN - 1 - i];
}
/* Validate public key - TinyCrypt will check if it's on the curve */
/* uECC_valid_public_key returns 0 if valid, negative value if invalid */
if (uECC_valid_public_key(pub_be, uECC_secp256r1()) < 0) {
SMP_TRACE_ERROR("%s, Invalid Public key. uECC_valid_public_key failed\n", __func__);
reason = SMP_INVALID_PARAMETERS;
smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
memset(pub_be, 0, sizeof(pub_be));
return;
}
/* Clear sensitive data from stack */
memset(pub_be, 0, sizeof(pub_be));
}
#else
if (!ECC_CheckPointIsInElliCur_P256((Point *)&p_cb->peer_publ_key)) {
SMP_TRACE_ERROR("%s, Invalid Public key.", __func__);
smp_sm_event(p_cb, SMP_AUTH_CMPL_EVT, &reason);
return;
}
#endif /* SMP_CRYPTO_MBEDTLS */
p_cb->flags |= SMP_PAIR_FLAG_HAVE_PEER_PUBL_KEY;
smp_wait_for_both_public_keys(p_cb, NULL);
@@ -35,7 +35,9 @@
#include "stack/hcimsgs.h"
#include "stack/btu.h"
#if (SMP_CRYPTO_STACK_NATIVE == TRUE)
#include "p_256_ecc_pp.h"
#endif
#include "osi/allocator.h"
/*******************************************************************************
@@ -51,12 +53,16 @@ void SMP_Init(void)
{
#if SMP_DYNAMIC_MEMORY
smp_cb_ptr = (tSMP_CB *)osi_malloc(sizeof(tSMP_CB));
#if (SMP_CRYPTO_STACK_NATIVE == TRUE)
curve_ptr = (elliptic_curve_t *)osi_malloc(sizeof(elliptic_curve_t));
curve_p256_ptr = (elliptic_curve_t *)osi_malloc(sizeof(elliptic_curve_t));
#endif
#endif
memset(&smp_cb, 0, sizeof(tSMP_CB));
#if (SMP_CRYPTO_STACK_NATIVE == TRUE)
memset(&curve, 0, sizeof(elliptic_curve_t));
memset(&curve_p256, 0, sizeof(elliptic_curve_t));
#endif
#if defined(SMP_INITIAL_TRACE_LEVEL)
smp_cb.trace_level = SMP_INITIAL_TRACE_LEVEL;
@@ -66,8 +72,10 @@ void SMP_Init(void)
SMP_TRACE_EVENT ("%s", __FUNCTION__);
smp_l2cap_if_init();
#if (SMP_CRYPTO_STACK_NATIVE == TRUE)
/* initialization of P-256 parameters */
p_256_init_curve(KEY_LENGTH_DWORDS_P256);
#endif
}
void SMP_Free(void)
@@ -75,8 +83,10 @@ void SMP_Free(void)
memset(&smp_cb, 0, sizeof(tSMP_CB));
#if SMP_DYNAMIC_MEMORY
FREE_AND_RESET(smp_cb_ptr);
#if (SMP_CRYPTO_STACK_NATIVE == TRUE)
FREE_AND_RESET(curve_ptr);
FREE_AND_RESET(curve_p256_ptr);
#endif
#endif /* #if SMP_DYNAMIC_MEMORY */
}
+221 -28
View File
@@ -32,7 +32,15 @@
#include "stack/btm_ble_api.h"
#include "smp_int.h"
#include "stack/hcimsgs.h"
#if (SMP_CRYPTO_MBEDTLS == TRUE)
#include "psa/crypto.h"
#elif (SMP_CRYPTO_TINYCRYPT == TRUE)
#include "tinycrypt/aes.h"
#include "tinycrypt/cmac_mode.h"
#include "tinycrypt/constants.h"
#endif
#if (SMP_CRYPTO_STACK_NATIVE == TRUE)
typedef struct {
UINT8 *text;
UINT16 len;
@@ -46,6 +54,7 @@ const BT_OCTET16 const_Rb = {
0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
#endif /* SMP_CRYPTO_STACK_NATIVE == TRUE */
void print128(BT_OCTET16 x, const UINT8 *key_name)
{
@@ -75,6 +84,7 @@ void print128(BT_OCTET16 x, const UINT8 *key_name)
** Returns void
**
*******************************************************************************/
#if (SMP_CRYPTO_STACK_NATIVE == TRUE)
static void padding ( BT_OCTET16 dest, UINT8 length )
{
UINT8 i, *p = dest;
@@ -83,6 +93,7 @@ static void padding ( BT_OCTET16 dest, UINT8 length )
p[BT_OCTET16_LEN - i - 1] = ( i == length ) ? 0x80 : 0;
}
}
/*******************************************************************************
**
** Function leftshift_onebit
@@ -104,6 +115,8 @@ static void leftshift_onebit(UINT8 *input, UINT8 *output)
}
return;
}
#endif /* SMP_CRYPTO_STACK_NATIVE == TRUE */
/*******************************************************************************
**
** Function cmac_aes_cleanup
@@ -113,6 +126,7 @@ static void leftshift_onebit(UINT8 *input, UINT8 *output)
** Returns void
**
*******************************************************************************/
#if (SMP_CRYPTO_STACK_NATIVE == TRUE)
static void cmac_aes_cleanup(void)
{
if (cmac_cb.text != NULL) {
@@ -167,11 +181,12 @@ static BOOLEAN cmac_aes_k_calculate(BT_OCTET16 key, UINT8 *p_signature, UINT16 t
return FALSE;
}
}
/*******************************************************************************
**
** Function cmac_prepare_last_block
**
** Description This function proceeed to prepare the last block of message
** Description This function proceed to prepare the last block of message
** Mn depending on the size of the message.
**
** Returns void
@@ -197,6 +212,8 @@ static void cmac_prepare_last_block (BT_OCTET16 k1, BT_OCTET16 k2)
smp_xor_128(&cmac_cb.text[0], k2);
}
}
#endif /* SMP_CRYPTO_STACK_NATIVE == TRUE */
/*******************************************************************************
**
** Function cmac_subkey_cont
@@ -206,6 +223,7 @@ static void cmac_prepare_last_block (BT_OCTET16 k1, BT_OCTET16 k2)
** Returns void
**
*******************************************************************************/
#if (SMP_CRYPTO_STACK_NATIVE == TRUE)
static void cmac_subkey_cont(tSMP_ENC *p)
{
UINT8 k1[BT_OCTET16_LEN], k2[BT_OCTET16_LEN];
@@ -262,6 +280,8 @@ static BOOLEAN cmac_generate_subkey(BT_OCTET16 key)
return ret;
}
#endif /* SMP_CRYPTO_STACK_NATIVE == TRUE */
/*******************************************************************************
**
** Function aes_cipher_msg_auth_code
@@ -271,7 +291,7 @@ static BOOLEAN cmac_generate_subkey(BT_OCTET16 key)
** Parameters key - CMAC key in little endian order, expect SRK when used by SMP.
** input - text to be signed in little endian byte order.
** length - length of the input in byte.
** tlen - lenth of mac desired
** tlen - length of mac desired
** p_signature - data pointer to where signed data to be stored, tlen long.
**
** Returns FALSE if out of resources, TRUE in other cases.
@@ -280,43 +300,216 @@ static BOOLEAN cmac_generate_subkey(BT_OCTET16 key)
BOOLEAN aes_cipher_msg_auth_code(BT_OCTET16 key, UINT8 *input, UINT16 length,
UINT16 tlen, UINT8 *p_signature)
{
UINT16 len, diff;
UINT16 n = (length + BT_OCTET16_LEN - 1) / BT_OCTET16_LEN; /* n is number of rounds */
BOOLEAN ret = FALSE;
SMP_TRACE_EVENT ("%s", __func__);
if (n == 0) {
n = 1;
#if (SMP_CRYPTO_MBEDTLS == TRUE)
{
/*
* PSA Crypto CMAC implementation.
* Bluedroid uses little-endian, PSA uses big-endian.
* We reverse the key and input, then reverse the output.
*/
psa_status_t status;
psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_key_id_t key_id = 0;
psa_mac_operation_t operation = PSA_MAC_OPERATION_INIT;
UINT8 key_be[BT_OCTET16_LEN];
UINT8 *input_be = NULL;
UINT8 mac_be[BT_OCTET16_LEN];
size_t mac_len = 0;
SMP_TRACE_DEBUG("AES128_CMAC (PSA) started, length = %d", length);
/* Convert key from little-endian to big-endian */
for (int i = 0; i < BT_OCTET16_LEN; i++) {
key_be[i] = key[BT_OCTET16_LEN - 1 - i];
}
/* Allocate and convert input from little-endian to big-endian */
if (length > 0) {
input_be = (UINT8 *)osi_malloc(length);
if (input_be == NULL) {
SMP_TRACE_ERROR("No resources for input_be");
return FALSE;
}
for (UINT16 i = 0; i < length; i++) {
input_be[i] = input[length - 1 - i];
}
}
/* Import the key */
psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_SIGN_MESSAGE);
psa_set_key_algorithm(&key_attributes, PSA_ALG_CMAC);
psa_set_key_type(&key_attributes, PSA_KEY_TYPE_AES);
psa_set_key_bits(&key_attributes, 128);
status = psa_import_key(&key_attributes, key_be, BT_OCTET16_LEN, &key_id);
psa_reset_key_attributes(&key_attributes);
if (status != PSA_SUCCESS) {
SMP_TRACE_ERROR("psa_import_key failed: %d", status);
if (input_be) osi_free(input_be);
return FALSE;
}
/* Setup MAC operation */
status = psa_mac_sign_setup(&operation, key_id, PSA_ALG_CMAC);
if (status != PSA_SUCCESS) {
SMP_TRACE_ERROR("psa_mac_sign_setup failed: %d", status);
psa_destroy_key(key_id);
if (input_be) osi_free(input_be);
return FALSE;
}
/* Update with input data */
if (length > 0 && input_be != NULL) {
status = psa_mac_update(&operation, input_be, length);
if (status != PSA_SUCCESS) {
SMP_TRACE_ERROR("psa_mac_update failed: %d", status);
psa_mac_abort(&operation);
psa_destroy_key(key_id);
osi_free(input_be);
return FALSE;
}
osi_free(input_be);
}
/* Finish and get MAC */
status = psa_mac_sign_finish(&operation, mac_be, sizeof(mac_be), &mac_len);
psa_destroy_key(key_id);
if (status != PSA_SUCCESS) {
SMP_TRACE_ERROR("psa_mac_sign_finish failed: %d", status);
psa_mac_abort(&operation);
return FALSE;
}
/* Convert MAC from big-endian to little-endian and truncate to tlen bytes */
for (UINT16 i = 0; i < tlen && i < BT_OCTET16_LEN; i++) {
p_signature[i] = mac_be[BT_OCTET16_LEN - 1 - i];
}
/* Clear sensitive data from stack */
memset(key_be, 0, sizeof(key_be));
ret = TRUE;
}
len = n * BT_OCTET16_LEN;
#elif (SMP_CRYPTO_TINYCRYPT == TRUE)
{
/*
* TinyCrypt CMAC implementation.
* Bluedroid uses little-endian, TinyCrypt uses big-endian.
* We reverse the key and input, then reverse the output.
*/
struct tc_aes_key_sched_struct sched;
struct tc_cmac_struct state;
UINT8 key_be[BT_OCTET16_LEN];
UINT8 *input_be = NULL;
UINT8 mac_be[BT_OCTET16_LEN];
SMP_TRACE_DEBUG("AES128_CMAC started, allocate buffer size = %d", len);
/* allocate a memory space of multiple of 16 bytes to hold text */
if ((cmac_cb.text = (UINT8 *)osi_malloc(len)) != NULL) {
cmac_cb.round = n;
SMP_TRACE_DEBUG("AES128_CMAC (TinyCrypt) started, length = %d", length);
memset(cmac_cb.text, 0, len);
diff = len - length;
/* Convert key from little-endian to big-endian */
for (int i = 0; i < BT_OCTET16_LEN; i++) {
key_be[i] = key[BT_OCTET16_LEN - 1 - i];
}
if (input != NULL && length > 0) {
memcpy(&cmac_cb.text[diff] , input, (int)length);
cmac_cb.len = length;
/* Setup CMAC */
if (tc_cmac_setup(&state, key_be, &sched) == TC_CRYPTO_FAIL) {
SMP_TRACE_ERROR("tc_cmac_setup failed");
memset(key_be, 0, sizeof(key_be));
memset(&sched, 0, sizeof(sched));
return FALSE;
}
/* Allocate and convert input from little-endian to big-endian */
if (length > 0) {
input_be = (UINT8 *)osi_malloc(length);
if (input_be == NULL) {
SMP_TRACE_ERROR("No resources for input_be");
tc_cmac_erase(&state);
memset(key_be, 0, sizeof(key_be));
memset(&sched, 0, sizeof(sched));
return FALSE;
}
for (UINT16 i = 0; i < length; i++) {
input_be[i] = input[length - 1 - i];
}
/* Update CMAC with input data */
if (tc_cmac_update(&state, input_be, length) == TC_CRYPTO_FAIL) {
SMP_TRACE_ERROR("tc_cmac_update failed");
osi_free(input_be);
tc_cmac_erase(&state);
memset(key_be, 0, sizeof(key_be));
memset(&sched, 0, sizeof(sched));
return FALSE;
}
osi_free(input_be);
}
/* Finalize CMAC */
if (tc_cmac_final(mac_be, &state) == TC_CRYPTO_FAIL) {
SMP_TRACE_ERROR("tc_cmac_final failed");
tc_cmac_erase(&state);
memset(key_be, 0, sizeof(key_be));
memset(&sched, 0, sizeof(sched));
return FALSE;
}
/* Convert MAC from big-endian to little-endian and truncate to tlen bytes */
for (UINT16 i = 0; i < tlen && i < BT_OCTET16_LEN; i++) {
p_signature[i] = mac_be[BT_OCTET16_LEN - 1 - i];
}
/* Clear sensitive data from stack */
tc_cmac_erase(&state);
memset(key_be, 0, sizeof(key_be));
memset(mac_be, 0, sizeof(mac_be));
memset(&sched, 0, sizeof(sched));
ret = TRUE;
}
#else
{
UINT16 len, diff;
UINT16 n = (length + BT_OCTET16_LEN - 1) / BT_OCTET16_LEN;
if (n == 0) {
n = 1;
}
len = n * BT_OCTET16_LEN;
SMP_TRACE_DEBUG("AES128_CMAC started, allocate buffer size = %d", len);
/* allocate a memory space of multiple of 16 bytes to hold text */
if ((cmac_cb.text = (UINT8 *)osi_malloc(len)) != NULL) {
cmac_cb.round = n;
memset(cmac_cb.text, 0, len);
diff = len - length;
if (input != NULL && length > 0) {
memcpy(&cmac_cb.text[diff] , input, (int)length);
cmac_cb.len = length;
} else {
cmac_cb.len = 0;
}
/* prepare calculation for subkey s and last block of data */
if (cmac_generate_subkey(key)) {
/* start calculation */
ret = cmac_aes_k_calculate(key, p_signature, tlen);
}
/* clean up */
cmac_aes_cleanup();
} else {
cmac_cb.len = 0;
ret = FALSE;
SMP_TRACE_ERROR("No resources");
}
/* prepare calculation for subkey s and last block of data */
if (cmac_generate_subkey(key)) {
/* start calculation */
ret = cmac_aes_k_calculate(key, p_signature, tlen);
}
/* clean up */
cmac_aes_cleanup();
} else {
ret = FALSE;
SMP_TRACE_ERROR("No resources");
}
#endif /* SMP_CRYPTO_MBEDTLS */
return ret;
}
+261 -13
View File
@@ -34,8 +34,18 @@
#include "btm_int.h"
#include "btm_ble_int.h"
#include "stack/hcimsgs.h"
#if (SMP_CRYPTO_MBEDTLS == TRUE)
#include "psa/crypto.h"
#elif (SMP_CRYPTO_TINYCRYPT == TRUE)
#include "tinycrypt/aes.h"
#include "tinycrypt/cmac_mode.h"
#include "tinycrypt/ecc_dh.h"
#include "tinycrypt/ecc.h"
#include "tinycrypt/constants.h"
#else
#include "aes.h"
#include "p_256_ecc_pp.h"
#endif /* SMP_CRYPTO_MBEDTLS */
#include "device/controller.h"
#ifndef SMP_MAX_ENC_REPEAT
@@ -159,12 +169,11 @@ BOOLEAN smp_encrypt_data (UINT8 *key, UINT8 key_len,
UINT8 *plain_text, UINT8 pt_len,
tSMP_ENC *p_out)
{
aes_context ctx;
UINT8 *p_start = NULL;
UINT8 *p = NULL;
UINT8 *p_rev_data = NULL; /* input data in big endilan format */
UINT8 *p_rev_key = NULL; /* input key in big endilan format */
UINT8 *p_rev_output = NULL; /* encrypted output in big endilan format */
UINT8 *p_rev_data = NULL; /* input data in big endian format */
UINT8 *p_rev_key = NULL; /* input key in big endian format */
UINT8 *p_rev_output = NULL; /* encrypted output in big endian format */
SMP_TRACE_DEBUG ("%s\n", __func__);
if ( (p_out == NULL ) || (key_len != SMP_ENCRYT_KEY_SIZE) ) {
@@ -194,8 +203,67 @@ BOOLEAN smp_encrypt_data (UINT8 *key, UINT8 key_len,
smp_debug_print_nbyte_little_endian(p_start, (const UINT8 *)"Plain text", SMP_ENCRYT_DATA_SIZE);
#endif
p_rev_output = p;
aes_set_key(p_rev_key, SMP_ENCRYT_KEY_SIZE, &ctx);
bluedroid_aes_encrypt(p_rev_data, p, &ctx); /* outputs in byte 48 to byte 63 */
#if (SMP_CRYPTO_MBEDTLS == TRUE)
{
psa_status_t status;
psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_key_id_t key_id = 0;
size_t output_len = 0;
psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_ENCRYPT);
psa_set_key_algorithm(&key_attributes, PSA_ALG_ECB_NO_PADDING);
psa_set_key_type(&key_attributes, PSA_KEY_TYPE_AES);
psa_set_key_bits(&key_attributes, 128);
status = psa_import_key(&key_attributes, p_rev_key, SMP_ENCRYT_KEY_SIZE, &key_id);
psa_reset_key_attributes(&key_attributes);
if (status != PSA_SUCCESS) {
SMP_TRACE_ERROR("%s psa_import_key failed: %d\n", __func__, status);
osi_free(p_start);
return FALSE;
}
status = psa_cipher_encrypt(key_id, PSA_ALG_ECB_NO_PADDING, p_rev_data,
SMP_ENCRYT_DATA_SIZE, p_rev_output, SMP_ENCRYT_DATA_SIZE, &output_len);
psa_destroy_key(key_id);
if (status != PSA_SUCCESS || output_len != SMP_ENCRYT_DATA_SIZE) {
SMP_TRACE_ERROR("%s psa_cipher_encrypt failed: %d\n", __func__, status);
osi_free(p_start);
return FALSE;
}
}
#elif (SMP_CRYPTO_TINYCRYPT == TRUE)
{
struct tc_aes_key_sched_struct sched;
/* TinyCrypt expects big-endian key and data */
if (tc_aes128_set_encrypt_key(&sched, p_rev_key) == TC_CRYPTO_FAIL) {
SMP_TRACE_ERROR("%s tc_aes128_set_encrypt_key failed\n", __func__);
memset(&sched, 0, sizeof(sched));
osi_free(p_start);
return FALSE;
}
if (tc_aes_encrypt(p_rev_output, p_rev_data, &sched) == TC_CRYPTO_FAIL) {
SMP_TRACE_ERROR("%s tc_aes_encrypt failed\n", __func__);
memset(&sched, 0, sizeof(sched));
osi_free(p_start);
return FALSE;
}
/* Clear sensitive data from key schedule */
memset(&sched, 0, sizeof(sched));
}
#else
{
aes_context ctx;
aes_set_key(p_rev_key, SMP_ENCRYT_KEY_SIZE, &ctx);
bluedroid_aes_encrypt(p_rev_data, p_rev_output, &ctx); /* outputs in byte 48 to byte 63 */
}
#endif /* SMP_CRYPTO_MBEDTLS */
p = p_out->param_buf;
REVERSE_ARRAY_TO_STREAM (p, p_rev_output, SMP_ENCRYT_DATA_SIZE);
@@ -207,6 +275,8 @@ BOOLEAN smp_encrypt_data (UINT8 *key, UINT8 key_len,
p_out->status = HCI_SUCCESS;
p_out->opcode = HCI_BLE_ENCRYPT;
/* Clear sensitive data (including key at byte 32-47) before freeing */
memset(p_start, 0, SMP_ENCRYT_DATA_SIZE * 4);
osi_free(p_start);
return TRUE;
@@ -1118,8 +1188,6 @@ void smp_continue_private_key_creation (tSMP_CB *p_cb, tBTM_RAND_ENC *p)
*******************************************************************************/
void smp_process_private_key(tSMP_CB *p_cb)
{
Point public_key;
BT_OCTET32 private_key;
tSMP_LOC_OOB_DATA *p_loc_oob = &p_cb->sc_oob_data.loc_oob_data;
SMP_TRACE_DEBUG ("%s", __FUNCTION__);
@@ -1131,10 +1199,90 @@ void smp_process_private_key(tSMP_CB *p_cb)
memcpy(p_cb->loc_publ_key.y, p_loc_oob->publ_key_used.y, BT_OCTET32_LEN);
memcpy(p_cb->local_random, p_loc_oob->randomizer, BT_OCTET16_LEN);
} else {
#if (SMP_CRYPTO_MBEDTLS == TRUE)
psa_status_t status;
psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_key_id_t key_id = 0;
UINT8 priv_be[BT_OCTET32_LEN];
UINT8 pub_be[BT_OCTET32_LEN + BT_OCTET32_LEN + 1]; /* 0x04 || X (32 bytes) || Y (32 bytes) */
size_t pub_len = 0;
/* Convert private key from little-endian to big-endian */
for (int i = 0; i < BT_OCTET32_LEN; i++) {
priv_be[i] = p_cb->private_key[BT_OCTET32_LEN - 1 - i];
}
/* Import the private key */
psa_set_key_type(&key_attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
psa_set_key_bits(&key_attributes, 256);
psa_set_key_algorithm(&key_attributes, PSA_ALG_ECDH);
psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_DERIVE | PSA_KEY_USAGE_EXPORT);
status = psa_import_key(&key_attributes, priv_be, BT_OCTET32_LEN, &key_id);
psa_reset_key_attributes(&key_attributes);
if (status != PSA_SUCCESS) {
SMP_TRACE_ERROR("%s psa_import_key failed: %d\n", __FUNCTION__, status);
goto psa_pubkey_cleanup;
}
/* Export public key */
status = psa_export_public_key(key_id, pub_be, sizeof(pub_be), &pub_len);
if (status != PSA_SUCCESS || pub_len != (BT_OCTET32_LEN + BT_OCTET32_LEN + 1)) {
SMP_TRACE_ERROR("%s psa_export_public_key failed: %d\n", __FUNCTION__, status);
goto psa_pubkey_cleanup;
}
/* Convert X and Y from big-endian to little-endian */
/* pub_be: 0x04 || X (32 bytes) || Y (32 bytes) */
for (int i = 0; i < BT_OCTET32_LEN; i++) {
p_cb->loc_publ_key.x[i] = pub_be[1 + BT_OCTET32_LEN - 1 - i];
p_cb->loc_publ_key.y[i] = pub_be[33 + BT_OCTET32_LEN - 1 - i];
}
psa_pubkey_cleanup:
psa_destroy_key(key_id);
/* Clear sensitive data from stack */
memset(priv_be, 0, sizeof(priv_be));
#elif (SMP_CRYPTO_TINYCRYPT == TRUE)
{
UINT8 pub_key[64]; /* TinyCrypt format: X (32 bytes) || Y (32 bytes), no prefix */
UINT8 priv_be[BT_OCTET32_LEN];
/* Convert private key from little-endian to big-endian */
for (int i = 0; i < BT_OCTET32_LEN; i++) {
priv_be[i] = p_cb->private_key[BT_OCTET32_LEN - 1 - i];
}
/* Compute public key from private key */
/* uECC_compute_public_key returns 1 if successful, 0 if failed */
if (uECC_compute_public_key(priv_be, pub_key, uECC_secp256r1()) != TC_CRYPTO_SUCCESS) {
SMP_TRACE_ERROR("%s uECC_compute_public_key failed\n", __FUNCTION__);
memset(priv_be, 0, sizeof(priv_be));
memset(pub_key, 0, sizeof(pub_key));
return;
}
/* Convert X and Y from big-endian to little-endian */
/* TinyCrypt format: X (32 bytes) || Y (32 bytes) */
for (int i = 0; i < BT_OCTET32_LEN; i++) {
p_cb->loc_publ_key.x[i] = pub_key[BT_OCTET32_LEN - 1 - i];
p_cb->loc_publ_key.y[i] = pub_key[BT_OCTET32_LEN + BT_OCTET32_LEN - 1 - i];
}
/* Clear sensitive data from stack */
memset(priv_be, 0, sizeof(priv_be));
memset(pub_key, 0, sizeof(pub_key));
}
#else
Point public_key;
BT_OCTET32 private_key;
memcpy(private_key, p_cb->private_key, BT_OCTET32_LEN);
ECC_PointMult(&public_key, &(curve_p256.G), (DWORD *) private_key, KEY_LENGTH_DWORDS_P256);
memcpy(p_cb->loc_publ_key.x, public_key.x, BT_OCTET32_LEN);
memcpy(p_cb->loc_publ_key.y, public_key.y, BT_OCTET32_LEN);
#endif /* SMP_CRYPTO_MBEDTLS */
}
smp_debug_print_nbyte_little_endian (p_cb->private_key, (const UINT8 *)"private",
@@ -1161,11 +1309,112 @@ void smp_process_private_key(tSMP_CB *p_cb)
*******************************************************************************/
void smp_compute_dhkey (tSMP_CB *p_cb)
{
SMP_TRACE_DEBUG ("%s\n", __FUNCTION__);
#if (SMP_CRYPTO_MBEDTLS == TRUE)
psa_status_t status;
psa_key_attributes_t key_attributes = PSA_KEY_ATTRIBUTES_INIT;
psa_key_id_t key_id = 0;
UINT8 priv_be[BT_OCTET32_LEN];
UINT8 peer_pub_be[BT_OCTET32_LEN + BT_OCTET32_LEN + 1]; /* 0x04 || X (32 bytes) || Y (32 bytes) */
UINT8 shared_secret[BT_OCTET32_LEN];
size_t output_len = 0;
/* Convert private key from little-endian to big-endian */
for (int i = 0; i < BT_OCTET32_LEN; i++) {
priv_be[i] = p_cb->private_key[BT_OCTET32_LEN - 1 - i];
}
/* Import the private key */
psa_set_key_type(&key_attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
psa_set_key_bits(&key_attributes, 256);
psa_set_key_algorithm(&key_attributes, PSA_ALG_ECDH);
psa_set_key_usage_flags(&key_attributes, PSA_KEY_USAGE_DERIVE);
status = psa_import_key(&key_attributes, priv_be, BT_OCTET32_LEN, &key_id);
psa_reset_key_attributes(&key_attributes);
if (status != PSA_SUCCESS) {
SMP_TRACE_ERROR("%s psa_import_key failed: %d\n", __FUNCTION__, status);
goto psa_dhkey_cleanup;
}
/* Construct peer public key in uncompressed format: 0x04 || X || Y */
peer_pub_be[0] = 0x04;
for (int i = 0; i < BT_OCTET32_LEN; i++) {
peer_pub_be[1 + i] = p_cb->peer_publ_key.x[BT_OCTET32_LEN - 1 - i];
peer_pub_be[33 + i] = p_cb->peer_publ_key.y[BT_OCTET32_LEN - 1 - i];
}
/* Compute ECDH shared secret */
status = psa_raw_key_agreement(PSA_ALG_ECDH, key_id, peer_pub_be, sizeof(peer_pub_be),
shared_secret, sizeof(shared_secret), &output_len);
if (status != PSA_SUCCESS || output_len != BT_OCTET32_LEN) {
SMP_TRACE_ERROR("%s psa_raw_key_agreement failed: %d\n", __FUNCTION__, status);
goto psa_dhkey_cleanup;
}
/* Convert shared secret from big-endian to little-endian for DHKey */
for (int i = 0; i < BT_OCTET32_LEN; i++) {
p_cb->dhkey[i] = shared_secret[BT_OCTET32_LEN - 1 - i];
}
psa_dhkey_cleanup:
psa_destroy_key(key_id);
/* Clear sensitive data from stack */
memset(priv_be, 0, sizeof(priv_be));
memset(shared_secret, 0, sizeof(shared_secret));
#elif (SMP_CRYPTO_TINYCRYPT == TRUE)
{
UINT8 priv_be[BT_OCTET32_LEN];
UINT8 peer_pub_be[64]; /* TinyCrypt format: X (32 bytes) || Y (32 bytes), no prefix */
UINT8 shared_secret[BT_OCTET32_LEN];
/* Convert private key from little-endian to big-endian */
for (int i = 0; i < BT_OCTET32_LEN; i++) {
priv_be[i] = p_cb->private_key[BT_OCTET32_LEN - 1 - i];
}
/* Convert peer public key from little-endian to big-endian */
/* TinyCrypt format: X (32 bytes) || Y (32 bytes), no prefix */
for (int i = 0; i < BT_OCTET32_LEN; i++) {
peer_pub_be[i] = p_cb->peer_publ_key.x[BT_OCTET32_LEN - 1 - i];
peer_pub_be[BT_OCTET32_LEN + i] = p_cb->peer_publ_key.y[BT_OCTET32_LEN - 1 - i];
}
/* Validate peer public key */
/* uECC_valid_public_key returns 0 if valid, negative value if invalid */
if (uECC_valid_public_key(peer_pub_be, uECC_secp256r1()) < 0) {
SMP_TRACE_ERROR("%s Invalid peer public key\n", __FUNCTION__);
memset(priv_be, 0, sizeof(priv_be));
memset(peer_pub_be, 0, sizeof(peer_pub_be));
return;
}
/* Compute ECDH shared secret */
/* uECC_shared_secret returns TC_CRYPTO_SUCCESS (1) if successful, TC_CRYPTO_FAIL (0) if failed */
if (uECC_shared_secret(peer_pub_be, priv_be, shared_secret, uECC_secp256r1()) != TC_CRYPTO_SUCCESS) {
SMP_TRACE_ERROR("%s uECC_shared_secret failed\n", __FUNCTION__);
memset(priv_be, 0, sizeof(priv_be));
memset(peer_pub_be, 0, sizeof(peer_pub_be));
memset(shared_secret, 0, sizeof(shared_secret));
return;
}
/* Convert shared secret from big-endian to little-endian for DHKey */
for (int i = 0; i < BT_OCTET32_LEN; i++) {
p_cb->dhkey[i] = shared_secret[BT_OCTET32_LEN - 1 - i];
}
/* Clear sensitive data from stack */
memset(priv_be, 0, sizeof(priv_be));
memset(peer_pub_be, 0, sizeof(peer_pub_be));
memset(shared_secret, 0, sizeof(shared_secret));
}
#else
Point peer_publ_key, new_publ_key;
BT_OCTET32 private_key;
SMP_TRACE_DEBUG ("%s\n", __FUNCTION__);
memcpy(private_key, p_cb->private_key, BT_OCTET32_LEN);
memcpy(peer_publ_key.x, p_cb->peer_publ_key.x, BT_OCTET32_LEN);
memcpy(peer_publ_key.y, p_cb->peer_publ_key.y, BT_OCTET32_LEN);
@@ -1173,8 +1422,9 @@ void smp_compute_dhkey (tSMP_CB *p_cb)
ECC_PointMult(&new_publ_key, &peer_publ_key, (DWORD *) private_key, KEY_LENGTH_DWORDS_P256);
memcpy(p_cb->dhkey, new_publ_key.x, BT_OCTET32_LEN);
#endif /* SMP_CRYPTO_MBEDTLS */
smp_debug_print_nbyte_little_endian (p_cb->dhkey, (const UINT8 *)"Old DHKey",
smp_debug_print_nbyte_little_endian (p_cb->dhkey, (const UINT8 *)"DHKey",
BT_OCTET32_LEN);
smp_debug_print_nbyte_little_endian (p_cb->private_key, (const UINT8 *)"private",
@@ -1183,8 +1433,6 @@ void smp_compute_dhkey (tSMP_CB *p_cb)
BT_OCTET32_LEN);
smp_debug_print_nbyte_little_endian (p_cb->peer_publ_key.y, (const UINT8 *)"rem public(y)",
BT_OCTET32_LEN);
smp_debug_print_nbyte_little_endian (p_cb->dhkey, (const UINT8 *)"Reverted DHKey",
BT_OCTET32_LEN);
}
/*******************************************************************************