You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
313 lines
9.7 KiB
313 lines
9.7 KiB
/****************************************************************************** |
|
* |
|
* Copyright (C) 2008-2012 Broadcom Corporation |
|
* |
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
* you may not use this file except in compliance with the License. |
|
* You may obtain a copy of the License at: |
|
* |
|
* http://www.apache.org/licenses/LICENSE-2.0 |
|
* |
|
* Unless required by applicable law or agreed to in writing, software |
|
* distributed under the License is distributed on an "AS IS" BASIS, |
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
* See the License for the specific language governing permissions and |
|
* limitations under the License. |
|
* |
|
******************************************************************************/ |
|
|
|
/****************************************************************************** |
|
* |
|
* This file contains the implementation of the AES128 CMAC algorithm. |
|
* |
|
******************************************************************************/ |
|
|
|
#include "bt_target.h" |
|
|
|
#include <stdio.h> |
|
#include <string.h> |
|
|
|
#include "btm_ble_api.h" |
|
#include "hcimsgs.h" |
|
#include "smp_int.h" |
|
|
|
typedef struct { |
|
uint8_t* text; |
|
uint16_t len; |
|
uint16_t round; |
|
} tCMAC_CB; |
|
|
|
tCMAC_CB cmac_cb; |
|
|
|
/* Rb for AES-128 as block cipher, LSB as [0] */ |
|
BT_OCTET16 const_Rb = {0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; |
|
|
|
void print128(BT_OCTET16 x, const uint8_t* key_name) { |
|
#if (SMP_DEBUG == TRUE && SMP_DEBUG_VERBOSE == TRUE) |
|
uint8_t* p = (uint8_t*)x; |
|
uint8_t i; |
|
|
|
SMP_TRACE_WARNING("%s(MSB ~ LSB) = ", key_name); |
|
|
|
for (i = 0; i < 4; i++) { |
|
SMP_TRACE_WARNING("%02x %02x %02x %02x", p[BT_OCTET16_LEN - i * 4 - 1], |
|
p[BT_OCTET16_LEN - i * 4 - 2], |
|
p[BT_OCTET16_LEN - i * 4 - 3], |
|
p[BT_OCTET16_LEN - i * 4 - 4]); |
|
} |
|
#endif |
|
} |
|
|
|
/******************************************************************************* |
|
* |
|
* Function padding |
|
* |
|
* Description utility function to padding the given text to be a 128 bits |
|
* data. The parameter dest is input and output parameter, it |
|
* must point to a BT_OCTET16_LEN memory space; where include |
|
* length bytes valid data. |
|
* |
|
* Returns void |
|
* |
|
******************************************************************************/ |
|
static void padding(BT_OCTET16 dest, uint8_t length) { |
|
uint8_t i, *p = dest; |
|
/* original last block */ |
|
for (i = length; i < BT_OCTET16_LEN; i++) |
|
p[BT_OCTET16_LEN - i - 1] = (i == length) ? 0x80 : 0; |
|
} |
|
/******************************************************************************* |
|
* |
|
* Function leftshift_onebit |
|
* |
|
* Description utility function to left shift one bit for a 128 bits value. |
|
* |
|
* Returns void |
|
* |
|
******************************************************************************/ |
|
static void leftshift_onebit(uint8_t* input, uint8_t* output) { |
|
uint8_t i, overflow = 0, next_overflow = 0; |
|
SMP_TRACE_EVENT("leftshift_onebit "); |
|
/* input[0] is LSB */ |
|
for (i = 0; i < BT_OCTET16_LEN; i++) { |
|
next_overflow = (input[i] & 0x80) ? 1 : 0; |
|
output[i] = (input[i] << 1) | overflow; |
|
overflow = next_overflow; |
|
} |
|
return; |
|
} |
|
/******************************************************************************* |
|
* |
|
* Function cmac_aes_cleanup |
|
* |
|
* Description clean up function for AES_CMAC algorithm. |
|
* |
|
* Returns void |
|
* |
|
******************************************************************************/ |
|
static void cmac_aes_cleanup(void) { |
|
osi_free(cmac_cb.text); |
|
memset(&cmac_cb, 0, sizeof(tCMAC_CB)); |
|
} |
|
|
|
/******************************************************************************* |
|
* |
|
* Function cmac_aes_k_calculate |
|
* |
|
* Description This function is the calculation of block cipher using |
|
* AES-128. |
|
* |
|
* Returns void |
|
* |
|
******************************************************************************/ |
|
static bool cmac_aes_k_calculate(BT_OCTET16 key, uint8_t* p_signature, |
|
uint16_t tlen) { |
|
tSMP_ENC output; |
|
uint8_t i = 1, err = 0; |
|
uint8_t x[16] = {0}; |
|
uint8_t* p_mac; |
|
|
|
SMP_TRACE_EVENT("cmac_aes_k_calculate "); |
|
|
|
while (i <= cmac_cb.round) { |
|
smp_xor_128(&cmac_cb.text[(cmac_cb.round - i) * BT_OCTET16_LEN], |
|
x); /* Mi' := Mi (+) X */ |
|
|
|
if (!SMP_Encrypt(key, BT_OCTET16_LEN, |
|
&cmac_cb.text[(cmac_cb.round - i) * BT_OCTET16_LEN], |
|
BT_OCTET16_LEN, &output)) { |
|
err = 1; |
|
break; |
|
} |
|
|
|
memcpy(x, output.param_buf, BT_OCTET16_LEN); |
|
i++; |
|
} |
|
|
|
if (!err) { |
|
p_mac = output.param_buf + (BT_OCTET16_LEN - tlen); |
|
memcpy(p_signature, p_mac, tlen); |
|
|
|
SMP_TRACE_DEBUG("tlen = %d p_mac = %d", tlen, p_mac); |
|
SMP_TRACE_DEBUG( |
|
"p_mac[0] = 0x%02x p_mac[1] = 0x%02x p_mac[2] = 0x%02x p_mac[3] = " |
|
"0x%02x", |
|
*p_mac, *(p_mac + 1), *(p_mac + 2), *(p_mac + 3)); |
|
SMP_TRACE_DEBUG( |
|
"p_mac[4] = 0x%02x p_mac[5] = 0x%02x p_mac[6] = 0x%02x p_mac[7] = " |
|
"0x%02x", |
|
*(p_mac + 4), *(p_mac + 5), *(p_mac + 6), *(p_mac + 7)); |
|
|
|
return true; |
|
|
|
} else |
|
return false; |
|
} |
|
/******************************************************************************* |
|
* |
|
* Function cmac_prepare_last_block |
|
* |
|
* Description This function proceeed to prepare the last block of message |
|
* Mn depending on the size of the message. |
|
* |
|
* Returns void |
|
* |
|
******************************************************************************/ |
|
static void cmac_prepare_last_block(BT_OCTET16 k1, BT_OCTET16 k2) { |
|
// uint8_t x[16] = {0}; |
|
bool flag; |
|
|
|
SMP_TRACE_EVENT("cmac_prepare_last_block "); |
|
/* last block is a complete block set flag to 1 */ |
|
flag = |
|
((cmac_cb.len % BT_OCTET16_LEN) == 0 && cmac_cb.len != 0) ? true : false; |
|
|
|
SMP_TRACE_WARNING("flag = %d round = %d", flag, cmac_cb.round); |
|
|
|
if (flag) { /* last block is complete block */ |
|
smp_xor_128(&cmac_cb.text[0], k1); |
|
} else /* padding then xor with k2 */ |
|
{ |
|
padding(&cmac_cb.text[0], (uint8_t)(cmac_cb.len % 16)); |
|
|
|
smp_xor_128(&cmac_cb.text[0], k2); |
|
} |
|
} |
|
/******************************************************************************* |
|
* |
|
* Function cmac_subkey_cont |
|
* |
|
* Description This is the callback function when CIPHk(0[128]) is |
|
* completed. |
|
* |
|
* Returns void |
|
* |
|
******************************************************************************/ |
|
static void cmac_subkey_cont(tSMP_ENC* p) { |
|
uint8_t k1[BT_OCTET16_LEN], k2[BT_OCTET16_LEN]; |
|
uint8_t* pp = p->param_buf; |
|
SMP_TRACE_EVENT("cmac_subkey_cont "); |
|
print128(pp, (const uint8_t*)"K1 before shift"); |
|
|
|
/* If MSB(L) = 0, then K1 = L << 1 */ |
|
if ((pp[BT_OCTET16_LEN - 1] & 0x80) != 0) { |
|
/* Else K1 = ( L << 1 ) (+) Rb */ |
|
leftshift_onebit(pp, k1); |
|
smp_xor_128(k1, const_Rb); |
|
} else { |
|
leftshift_onebit(pp, k1); |
|
} |
|
|
|
if ((k1[BT_OCTET16_LEN - 1] & 0x80) != 0) { |
|
/* K2 = (K1 << 1) (+) Rb */ |
|
leftshift_onebit(k1, k2); |
|
smp_xor_128(k2, const_Rb); |
|
} else { |
|
/* If MSB(K1) = 0, then K2 = K1 << 1 */ |
|
leftshift_onebit(k1, k2); |
|
} |
|
|
|
print128(k1, (const uint8_t*)"K1"); |
|
print128(k2, (const uint8_t*)"K2"); |
|
|
|
cmac_prepare_last_block(k1, k2); |
|
} |
|
/******************************************************************************* |
|
* |
|
* Function cmac_generate_subkey |
|
* |
|
* Description This is the function to generate the two subkeys. |
|
* |
|
* Parameters key - CMAC key, expect SRK when used by SMP. |
|
* |
|
* Returns void |
|
* |
|
******************************************************************************/ |
|
static bool cmac_generate_subkey(BT_OCTET16 key) { |
|
BT_OCTET16 z = {0}; |
|
bool ret = true; |
|
tSMP_ENC output; |
|
SMP_TRACE_EVENT(" cmac_generate_subkey"); |
|
|
|
if (SMP_Encrypt(key, BT_OCTET16_LEN, z, BT_OCTET16_LEN, &output)) { |
|
cmac_subkey_cont(&output); |
|
; |
|
} else |
|
ret = false; |
|
|
|
return ret; |
|
} |
|
/******************************************************************************* |
|
* |
|
* Function aes_cipher_msg_auth_code |
|
* |
|
* Description This is the AES-CMAC Generation Function with tlen |
|
* implemented. |
|
* |
|
* 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 |
|
* p_signature - data pointer to where signed data to be |
|
* stored, tlen long. |
|
* |
|
* Returns false if out of resources, true in other cases. |
|
* |
|
******************************************************************************/ |
|
bool aes_cipher_msg_auth_code(BT_OCTET16 key, uint8_t* input, uint16_t length, |
|
uint16_t tlen, uint8_t* p_signature) { |
|
uint16_t len, diff; |
|
uint16_t n = (length + BT_OCTET16_LEN - 1) / |
|
BT_OCTET16_LEN; /* n is number of rounds */ |
|
bool ret = false; |
|
|
|
SMP_TRACE_EVENT("%s", __func__); |
|
|
|
if (n == 0) n = 1; |
|
len = n * BT_OCTET16_LEN; |
|
|
|
SMP_TRACE_WARNING("AES128_CMAC started, allocate buffer size = %d", len); |
|
/* allocate a memory space of multiple of 16 bytes to hold text */ |
|
cmac_cb.text = (uint8_t*)osi_calloc(len); |
|
cmac_cb.round = n; |
|
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(); |
|
|
|
return ret; |
|
}
|
|
|