1 /******************************************************************************
2  *
3  *  Copyright 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 and AES CMAC algorithm.
22  *
23  ******************************************************************************/
24 
25 #include "stack/crypto_toolbox/aes.h"
26 #include "stack/crypto_toolbox/crypto_toolbox.h"
27 
28 #include <base/logging.h>
29 #include <base/strings/string_number_conversions.h>
30 
31 namespace crypto_toolbox {
32 
33 namespace {
34 
35 typedef struct {
36   uint8_t* text;
37   uint16_t len;
38   uint16_t round;
39 } tCMAC_CB;
40 
41 thread_local tCMAC_CB cmac_cb;
42 
43 /* Rb for AES-128 as block cipher, LSB as [0] */
44 Octet16 const_Rb{0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
45                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
46 
47 /** utility function to do an biteise exclusive-OR of two bit strings of the
48  * length of OCTET16_LEN. Result is stored in first argument.
49  */
xor_128(Octet16 * a,const Octet16 & b)50 static void xor_128(Octet16* a, const Octet16& b) {
51   CHECK(a);
52   uint8_t i, *aa = a->data();
53   const uint8_t* bb = b.data();
54 
55   for (i = 0; i < OCTET16_LEN; i++) {
56     aa[i] = aa[i] ^ bb[i];
57   }
58 }
59 }  // namespace
60 
61 /* This function computes AES_128(key, message) */
aes_128(const Octet16 & key,const Octet16 & message)62 Octet16 aes_128(const Octet16& key, const Octet16& message) {
63   Octet16 key_reversed;
64   Octet16 message_reversed;
65   Octet16 output;
66 
67   std::reverse_copy(key.begin(), key.end(), key_reversed.begin());
68   std::reverse_copy(message.begin(), message.end(), message_reversed.begin());
69 
70   aes_context ctx;
71   aes_set_key(key_reversed.data(), key_reversed.size(), &ctx);
72   aes_encrypt(message_reversed.data(), output.data(), &ctx);
73 
74   std::reverse(output.begin(), output.end());
75   return output;
76 }
77 
78 /** utility function to padding the given text to be a 128 bits data. The
79  * parameter dest is input and output parameter, it must point to a
80  * OCTET16_LEN memory space; where include length bytes valid data. */
padding(Octet16 * dest,uint8_t length)81 static void padding(Octet16* dest, uint8_t length) {
82   uint8_t i, *p = dest->data();
83   /* original last block */
84   for (i = length; i < OCTET16_LEN; i++)
85     p[OCTET16_LEN - i - 1] = (i == length) ? 0x80 : 0;
86 }
87 
88 /** utility function to left shift one bit for a 128 bits value. */
leftshift_onebit(uint8_t * input,uint8_t * output)89 static void leftshift_onebit(uint8_t* input, uint8_t* output) {
90   uint8_t i, overflow = 0, next_overflow = 0;
91   DVLOG(2) << __func__;
92   /* input[0] is LSB */
93   for (i = 0; i < 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 /** This function is the calculation of block cipher using AES-128. */
cmac_aes_k_calculate(const Octet16 & key)102 static Octet16 cmac_aes_k_calculate(const Octet16& key) {
103   Octet16 output;
104   Octet16 x{0};  // zero initialized
105 
106   DVLOG(2) << __func__;
107 
108   uint8_t i = 1;
109   while (i <= cmac_cb.round) {
110     /* Mi' := Mi (+) X  */
111     xor_128((Octet16*)&cmac_cb.text[(cmac_cb.round - i) * OCTET16_LEN], x);
112 
113     output = aes_128(key, &cmac_cb.text[(cmac_cb.round - i) * OCTET16_LEN],
114                      OCTET16_LEN);
115     x = output;
116     i++;
117   }
118 
119   return output;
120 }
121 
122 /** This function proceeed to prepare the last block of message Mn depending on
123  * the size of the message.
124  */
cmac_prepare_last_block(const Octet16 & k1,const Octet16 & k2)125 static void cmac_prepare_last_block(const Octet16& k1, const Octet16& k2) {
126   //    uint8_t     x[16] = {0};
127   bool flag;
128 
129   DVLOG(2) << __func__;
130   /* last block is a complete block set flag to 1 */
131   flag = ((cmac_cb.len % OCTET16_LEN) == 0 && cmac_cb.len != 0) ? true : false;
132 
133   DVLOG(2) << "flag=" << flag << " round=" << cmac_cb.round;
134 
135   if (flag) { /* last block is complete block */
136     xor_128((Octet16*)&cmac_cb.text[0], k1);
137   } else /* padding then xor with k2 */
138   {
139     padding((Octet16*)&cmac_cb.text[0], (uint8_t)(cmac_cb.len % 16));
140 
141     xor_128((Octet16*)&cmac_cb.text[0], k2);
142   }
143 }
144 
145 /** This is the function to generate the two subkeys.
146  * |key| is CMAC key, expect SRK when used by SMP.
147  */
cmac_generate_subkey(const Octet16 & key)148 static void cmac_generate_subkey(const Octet16& key) {
149   DVLOG(2) << __func__;
150 
151   Octet16 zero{};
152   Octet16 p = aes_128(key, zero.data(), OCTET16_LEN);
153 
154   Octet16 k1, k2;
155   uint8_t* pp = p.data();
156 
157   /* If MSB(L) = 0, then K1 = L << 1 */
158   if ((pp[OCTET16_LEN - 1] & 0x80) != 0) {
159     /* Else K1 = ( L << 1 ) (+) Rb */
160     leftshift_onebit(pp, k1.data());
161     xor_128(&k1, const_Rb);
162   } else {
163     leftshift_onebit(pp, k1.data());
164   }
165 
166   if ((k1[OCTET16_LEN - 1] & 0x80) != 0) {
167     /* K2 =  (K1 << 1) (+) Rb */
168     leftshift_onebit(k1.data(), k2.data());
169     xor_128(&k2, const_Rb);
170   } else {
171     /* If MSB(K1) = 0, then K2 = K1 << 1 */
172     leftshift_onebit(k1.data(), k2.data());
173   }
174 
175   cmac_prepare_last_block(k1, k2);
176 }
177 
178 /** key - CMAC key in little endian order
179  *  input - text to be signed in little endian byte order.
180  *  length - length of the input in byte.
181  */
aes_cmac(const Octet16 & key,const uint8_t * input,uint16_t length)182 Octet16 aes_cmac(const Octet16& key, const uint8_t* input, uint16_t length) {
183   uint32_t len;
184   uint16_t diff;
185   /* n is number of rounds */
186   uint16_t n = (length + OCTET16_LEN - 1) / OCTET16_LEN;
187 
188   DVLOG(2) << __func__;
189 
190   if (n == 0) n = 1;
191   len = n * OCTET16_LEN;
192 
193   DVLOG(2) << "AES128_CMAC started, allocate buffer size=" << len;
194   /* allocate a memory space of multiple of 16 bytes to hold text  */
195   cmac_cb.text = (uint8_t*)alloca(len);
196   cmac_cb.round = n;
197   diff = len - length;
198 
199   if (input != NULL && length > 0) {
200     memcpy(&cmac_cb.text[diff], input, (int)length);
201     cmac_cb.len = length;
202   } else {
203     cmac_cb.len = 0;
204   }
205 
206   /* prepare calculation for subkey s and last block of data */
207   cmac_generate_subkey(key);
208   /* start calculation */
209   Octet16 signature = cmac_aes_k_calculate(key);
210 
211   /* clean up */
212   memset(&cmac_cb, 0, sizeof(tCMAC_CB));
213   // cmac_cb.text is auto-freed by alloca
214 
215   return signature;
216 }
217 
218 }  // namespace crypto_toolbox
219