1/******************************************************************************
2 *
3 *  Copyright (C) 2008-2012 Broadcom Corporation
4 *
5 *  Licensed under the Apache License, Version 2.0 (the "License");
6 *  you may not use this file except in compliance with the License.
7 *  You may obtain a copy of the License at:
8 *
9 *  http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 *
17 ******************************************************************************/
18
19/******************************************************************************
20 *
21 *  This file contains the implementation of the AES128 CMAC algorithm.
22 *
23 ******************************************************************************/
24
25#include "bt_target.h"
26
27#include <stdio.h>
28#include <string.h>
29
30#include "btm_ble_api.h"
31#include "hcimsgs.h"
32#include "smp_int.h"
33
34typedef struct {
35  uint8_t* text;
36  uint16_t len;
37  uint16_t round;
38} tCMAC_CB;
39
40tCMAC_CB cmac_cb;
41
42/* Rb for AES-128 as block cipher, LSB as [0] */
43BT_OCTET16 const_Rb = {0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
44                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
45
46void print128(BT_OCTET16 x, const uint8_t* key_name) {
47#if (SMP_DEBUG == TRUE && SMP_DEBUG_VERBOSE == TRUE)
48  uint8_t* p = (uint8_t*)x;
49  uint8_t i;
50
51  SMP_TRACE_WARNING("%s(MSB ~ LSB) = ", key_name);
52
53  for (i = 0; i < 4; i++) {
54    SMP_TRACE_WARNING("%02x %02x %02x %02x", p[BT_OCTET16_LEN - i * 4 - 1],
55                      p[BT_OCTET16_LEN - i * 4 - 2],
56                      p[BT_OCTET16_LEN - i * 4 - 3],
57                      p[BT_OCTET16_LEN - i * 4 - 4]);
58  }
59#endif
60}
61
62/*******************************************************************************
63 *
64 * Function         padding
65 *
66 * Description      utility function to padding the given text to be a 128 bits
67 *                  data. The parameter dest is input and output parameter, it
68 *                  must point to a BT_OCTET16_LEN memory space; where include
69 *                  length bytes valid data.
70 *
71 * Returns          void
72 *
73 ******************************************************************************/
74static void padding(BT_OCTET16 dest, uint8_t length) {
75  uint8_t i, *p = dest;
76  /* original last block */
77  for (i = length; i < BT_OCTET16_LEN; i++)
78    p[BT_OCTET16_LEN - i - 1] = (i == length) ? 0x80 : 0;
79}
80/*******************************************************************************
81 *
82 * Function         leftshift_onebit
83 *
84 * Description      utility function to left shift one bit for a 128 bits value.
85 *
86 * Returns          void
87 *
88 ******************************************************************************/
89static void leftshift_onebit(uint8_t* input, uint8_t* output) {
90  uint8_t i, overflow = 0, next_overflow = 0;
91  SMP_TRACE_EVENT("leftshift_onebit ");
92  /* input[0] is LSB */
93  for (i = 0; i < BT_OCTET16_LEN; i++) {
94    next_overflow = (input[i] & 0x80) ? 1 : 0;
95    output[i] = (input[i] << 1) | overflow;
96    overflow = next_overflow;
97  }
98  return;
99}
100/*******************************************************************************
101 *
102 * Function         cmac_aes_cleanup
103 *
104 * Description      clean up function for AES_CMAC algorithm.
105 *
106 * Returns          void
107 *
108 ******************************************************************************/
109static void cmac_aes_cleanup(void) {
110  osi_free(cmac_cb.text);
111  memset(&cmac_cb, 0, sizeof(tCMAC_CB));
112}
113
114/*******************************************************************************
115 *
116 * Function         cmac_aes_k_calculate
117 *
118 * Description      This function is the calculation of block cipher using
119 *                  AES-128.
120 *
121 * Returns          void
122 *
123 ******************************************************************************/
124static bool cmac_aes_k_calculate(BT_OCTET16 key, uint8_t* p_signature,
125                                 uint16_t tlen) {
126  tSMP_ENC output;
127  uint8_t i = 1, err = 0;
128  uint8_t x[16] = {0};
129  uint8_t* p_mac;
130
131  SMP_TRACE_EVENT("cmac_aes_k_calculate ");
132
133  while (i <= cmac_cb.round) {
134    smp_xor_128(&cmac_cb.text[(cmac_cb.round - i) * BT_OCTET16_LEN],
135                x); /* Mi' := Mi (+) X  */
136
137    if (!SMP_Encrypt(key, BT_OCTET16_LEN,
138                     &cmac_cb.text[(cmac_cb.round - i) * BT_OCTET16_LEN],
139                     BT_OCTET16_LEN, &output)) {
140      err = 1;
141      break;
142    }
143
144    memcpy(x, output.param_buf, BT_OCTET16_LEN);
145    i++;
146  }
147
148  if (!err) {
149    p_mac = output.param_buf + (BT_OCTET16_LEN - tlen);
150    memcpy(p_signature, p_mac, tlen);
151
152    SMP_TRACE_DEBUG("tlen = %d p_mac = %d", tlen, p_mac);
153    SMP_TRACE_DEBUG(
154        "p_mac[0] = 0x%02x p_mac[1] = 0x%02x p_mac[2] = 0x%02x p_mac[3] = "
155        "0x%02x",
156        *p_mac, *(p_mac + 1), *(p_mac + 2), *(p_mac + 3));
157    SMP_TRACE_DEBUG(
158        "p_mac[4] = 0x%02x p_mac[5] = 0x%02x p_mac[6] = 0x%02x p_mac[7] = "
159        "0x%02x",
160        *(p_mac + 4), *(p_mac + 5), *(p_mac + 6), *(p_mac + 7));
161
162    return true;
163
164  } else
165    return false;
166}
167/*******************************************************************************
168 *
169 * Function         cmac_prepare_last_block
170 *
171 * Description      This function proceeed to prepare the last block of message
172 *                  Mn depending on the size of the message.
173 *
174 * Returns          void
175 *
176 ******************************************************************************/
177static void cmac_prepare_last_block(BT_OCTET16 k1, BT_OCTET16 k2) {
178  //    uint8_t     x[16] = {0};
179  bool flag;
180
181  SMP_TRACE_EVENT("cmac_prepare_last_block ");
182  /* last block is a complete block set flag to 1 */
183  flag =
184      ((cmac_cb.len % BT_OCTET16_LEN) == 0 && cmac_cb.len != 0) ? true : false;
185
186  SMP_TRACE_WARNING("flag = %d round = %d", flag, cmac_cb.round);
187
188  if (flag) { /* last block is complete block */
189    smp_xor_128(&cmac_cb.text[0], k1);
190  } else /* padding then xor with k2 */
191  {
192    padding(&cmac_cb.text[0], (uint8_t)(cmac_cb.len % 16));
193
194    smp_xor_128(&cmac_cb.text[0], k2);
195  }
196}
197/*******************************************************************************
198 *
199 * Function         cmac_subkey_cont
200 *
201 * Description      This is the callback function when CIPHk(0[128]) is
202 *                  completed.
203 *
204 * Returns          void
205 *
206 ******************************************************************************/
207static void cmac_subkey_cont(tSMP_ENC* p) {
208  uint8_t k1[BT_OCTET16_LEN], k2[BT_OCTET16_LEN];
209  uint8_t* pp = p->param_buf;
210  SMP_TRACE_EVENT("cmac_subkey_cont ");
211  print128(pp, (const uint8_t*)"K1 before shift");
212
213  /* If MSB(L) = 0, then K1 = L << 1 */
214  if ((pp[BT_OCTET16_LEN - 1] & 0x80) != 0) {
215    /* Else K1 = ( L << 1 ) (+) Rb */
216    leftshift_onebit(pp, k1);
217    smp_xor_128(k1, const_Rb);
218  } else {
219    leftshift_onebit(pp, k1);
220  }
221
222  if ((k1[BT_OCTET16_LEN - 1] & 0x80) != 0) {
223    /* K2 =  (K1 << 1) (+) Rb */
224    leftshift_onebit(k1, k2);
225    smp_xor_128(k2, const_Rb);
226  } else {
227    /* If MSB(K1) = 0, then K2 = K1 << 1 */
228    leftshift_onebit(k1, k2);
229  }
230
231  print128(k1, (const uint8_t*)"K1");
232  print128(k2, (const uint8_t*)"K2");
233
234  cmac_prepare_last_block(k1, k2);
235}
236/*******************************************************************************
237 *
238 * Function         cmac_generate_subkey
239 *
240 * Description      This is the function to generate the two subkeys.
241 *
242 * Parameters       key - CMAC key, expect SRK when used by SMP.
243 *
244 * Returns          void
245 *
246 ******************************************************************************/
247static bool cmac_generate_subkey(BT_OCTET16 key) {
248  BT_OCTET16 z = {0};
249  bool ret = true;
250  tSMP_ENC output;
251  SMP_TRACE_EVENT(" cmac_generate_subkey");
252
253  if (SMP_Encrypt(key, BT_OCTET16_LEN, z, BT_OCTET16_LEN, &output)) {
254    cmac_subkey_cont(&output);
255    ;
256  } else
257    ret = false;
258
259  return ret;
260}
261/*******************************************************************************
262 *
263 * Function         aes_cipher_msg_auth_code
264 *
265 * Description      This is the AES-CMAC Generation Function with tlen
266 *                  implemented.
267 *
268 * Parameters       key - CMAC key in little endian order, expect SRK when used
269 *                        by SMP.
270 *                  input - text to be signed in little endian byte order.
271 *                  length - length of the input in byte.
272 *                  tlen - lenth of mac desired
273 *                  p_signature - data pointer to where signed data to be
274 *                                stored, tlen long.
275 *
276 * Returns          false if out of resources, true in other cases.
277 *
278 ******************************************************************************/
279bool aes_cipher_msg_auth_code(BT_OCTET16 key, uint8_t* input, uint16_t length,
280                              uint16_t tlen, uint8_t* p_signature) {
281  uint16_t len, diff;
282  uint16_t n = (length + BT_OCTET16_LEN - 1) /
283               BT_OCTET16_LEN; /* n is number of rounds */
284  bool ret = false;
285
286  SMP_TRACE_EVENT("%s", __func__);
287
288  if (n == 0) n = 1;
289  len = n * BT_OCTET16_LEN;
290
291  SMP_TRACE_WARNING("AES128_CMAC started, allocate buffer size = %d", len);
292  /* allocate a memory space of multiple of 16 bytes to hold text  */
293  cmac_cb.text = (uint8_t*)osi_calloc(len);
294  cmac_cb.round = n;
295  diff = len - length;
296
297  if (input != NULL && length > 0) {
298    memcpy(&cmac_cb.text[diff], input, (int)length);
299    cmac_cb.len = length;
300  } else {
301    cmac_cb.len = 0;
302  }
303
304  /* prepare calculation for subkey s and last block of data */
305  if (cmac_generate_subkey(key)) {
306    /* start calculation */
307    ret = cmac_aes_k_calculate(key, p_signature, tlen);
308  }
309  /* clean up */
310  cmac_aes_cleanup();
311
312  return ret;
313}
314