1 /*
2 * Copyright (c) 2020 Nordic Semiconductor ASA
3 * Copyright (c) 2017 Intel Corporation
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <string.h>
9
10 #include <zephyr.h>
11 #include <sys/byteorder.h>
12 #include <bluetooth/crypto.h>
13
14 #define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_CORE)
15 #define LOG_MODULE_NAME bt_aes_ccm
16 #include "common/log.h"
17
xor16(uint8_t * dst,const uint8_t * a,const uint8_t * b)18 static inline void xor16(uint8_t *dst, const uint8_t *a, const uint8_t *b)
19 {
20 dst[0] = a[0] ^ b[0];
21 dst[1] = a[1] ^ b[1];
22 dst[2] = a[2] ^ b[2];
23 dst[3] = a[3] ^ b[3];
24 dst[4] = a[4] ^ b[4];
25 dst[5] = a[5] ^ b[5];
26 dst[6] = a[6] ^ b[6];
27 dst[7] = a[7] ^ b[7];
28 dst[8] = a[8] ^ b[8];
29 dst[9] = a[9] ^ b[9];
30 dst[10] = a[10] ^ b[10];
31 dst[11] = a[11] ^ b[11];
32 dst[12] = a[12] ^ b[12];
33 dst[13] = a[13] ^ b[13];
34 dst[14] = a[14] ^ b[14];
35 dst[15] = a[15] ^ b[15];
36 }
37
38 /* pmsg is assumed to have the nonce already present in bytes 1-13 */
ccm_calculate_X0(const uint8_t key[16],const uint8_t * aad,uint8_t aad_len,size_t mic_size,uint8_t msg_len,uint8_t b[16],uint8_t X0[16])39 static int ccm_calculate_X0(const uint8_t key[16], const uint8_t *aad, uint8_t aad_len,
40 size_t mic_size, uint8_t msg_len, uint8_t b[16],
41 uint8_t X0[16])
42 {
43 int i, j, err;
44
45 /* X_0 = e(AppKey, flags || nonce || length) */
46 b[0] = (((mic_size - 2) / 2) << 3) | ((!!aad_len) << 6) | 0x01;
47
48 sys_put_be16(msg_len, b + 14);
49
50 err = bt_encrypt_be(key, b, X0);
51 if (err) {
52 return err;
53 }
54
55 /* If AAD is being used to authenticate, include it here */
56 if (aad_len) {
57 sys_put_be16(aad_len, b);
58
59 for (i = 0; i < sizeof(uint16_t); i++) {
60 b[i] = X0[i] ^ b[i];
61 }
62
63 j = 0;
64 aad_len += sizeof(uint16_t);
65 while (aad_len > 16) {
66 do {
67 b[i] = X0[i] ^ aad[j];
68 i++, j++;
69 } while (i < 16);
70
71 aad_len -= 16;
72 i = 0;
73
74 err = bt_encrypt_be(key, b, X0);
75 if (err) {
76 return err;
77 }
78 }
79
80 for (; i < aad_len; i++, j++) {
81 b[i] = X0[i] ^ aad[j];
82 }
83
84 for (i = aad_len; i < 16; i++) {
85 b[i] = X0[i];
86 }
87
88 err = bt_encrypt_be(key, b, X0);
89 if (err) {
90 return err;
91 }
92 }
93
94 return 0;
95 }
96
ccm_auth(const uint8_t key[16],uint8_t nonce[13],const uint8_t * cleartext_msg,size_t msg_len,const uint8_t * aad,size_t aad_len,uint8_t * mic,size_t mic_size)97 static int ccm_auth(const uint8_t key[16], uint8_t nonce[13],
98 const uint8_t *cleartext_msg, size_t msg_len, const uint8_t *aad,
99 size_t aad_len, uint8_t *mic, size_t mic_size)
100 {
101 uint8_t b[16], Xn[16], s0[16];
102 uint16_t blk_cnt, last_blk;
103 int err, j, i;
104
105 last_blk = msg_len % 16;
106 blk_cnt = (msg_len + 15) / 16;
107 if (!last_blk) {
108 last_blk = 16U;
109 }
110
111 b[0] = 0x01;
112 memcpy(b + 1, nonce, 13);
113
114 /* S[0] = e(AppKey, 0x01 || nonce || 0x0000) */
115 sys_put_be16(0x0000, &b[14]);
116
117 err = bt_encrypt_be(key, b, s0);
118 if (err) {
119 return err;
120 }
121
122 ccm_calculate_X0(key, aad, aad_len, mic_size, msg_len, b, Xn);
123
124 for (j = 0; j < blk_cnt; j++) {
125 /* X_1 = e(AppKey, X_0 ^ Payload[0-15]) */
126 if (j + 1 == blk_cnt) {
127 for (i = 0; i < last_blk; i++) {
128 b[i] = Xn[i] ^ cleartext_msg[(j * 16) + i];
129 }
130
131 memcpy(&b[i], &Xn[i], 16 - i);
132 } else {
133 xor16(b, Xn, &cleartext_msg[j * 16]);
134 }
135
136 err = bt_encrypt_be(key, b, Xn);
137 if (err) {
138 return err;
139 }
140 }
141
142 /* MIC = C_mic ^ X_1 */
143 for (i = 0; i < mic_size; i++) {
144 mic[i] = s0[i] ^ Xn[i];
145 }
146
147 return 0;
148 }
149
ccm_crypt(const uint8_t key[16],const uint8_t nonce[13],const uint8_t * in_msg,uint8_t * out_msg,size_t msg_len)150 static int ccm_crypt(const uint8_t key[16], const uint8_t nonce[13],
151 const uint8_t *in_msg, uint8_t *out_msg, size_t msg_len)
152 {
153 uint8_t a_i[16], s_i[16];
154 uint16_t last_blk, blk_cnt;
155 size_t i, j;
156 int err;
157
158 last_blk = msg_len % 16;
159 blk_cnt = (msg_len + 15) / 16;
160 if (!last_blk) {
161 last_blk = 16U;
162 }
163
164 a_i[0] = 0x01;
165 memcpy(&a_i[1], nonce, 13);
166
167 for (j = 0; j < blk_cnt; j++) {
168 /* S_1 = e(AppKey, 0x01 || nonce || 0x0001) */
169 sys_put_be16(j + 1, &a_i[14]);
170
171 err = bt_encrypt_be(key, a_i, s_i);
172 if (err) {
173 return err;
174 }
175
176 /* Encrypted = Payload[0-15] ^ C_1 */
177 if (j < blk_cnt - 1) {
178 xor16(&out_msg[j * 16], s_i, &in_msg[j * 16]);
179 } else {
180 for (i = 0; i < last_blk; i++) {
181 out_msg[(j * 16) + i] =
182 in_msg[(j * 16) + i] ^ s_i[i];
183 }
184 }
185 }
186 return 0;
187 }
188
bt_ccm_decrypt(const uint8_t key[16],uint8_t nonce[13],const uint8_t * enc_data,size_t len,const uint8_t * aad,size_t aad_len,uint8_t * plaintext,size_t mic_size)189 int bt_ccm_decrypt(const uint8_t key[16], uint8_t nonce[13],
190 const uint8_t *enc_data, size_t len, const uint8_t *aad,
191 size_t aad_len, uint8_t *plaintext, size_t mic_size)
192 {
193 uint8_t mic[16];
194
195 if (aad_len >= 0xff00 || mic_size > sizeof(mic)) {
196 return -EINVAL;
197 }
198
199 ccm_crypt(key, nonce, enc_data, plaintext, len);
200
201 ccm_auth(key, nonce, plaintext, len, aad, aad_len, mic, mic_size);
202
203 if (memcmp(mic, enc_data + len, mic_size)) {
204 return -EBADMSG;
205 }
206
207 return 0;
208 }
209
bt_ccm_encrypt(const uint8_t key[16],uint8_t nonce[13],const uint8_t * plaintext,size_t len,const uint8_t * aad,size_t aad_len,uint8_t * enc_data,size_t mic_size)210 int bt_ccm_encrypt(const uint8_t key[16], uint8_t nonce[13],
211 const uint8_t *plaintext, size_t len, const uint8_t *aad,
212 size_t aad_len, uint8_t *enc_data, size_t mic_size)
213 {
214 uint8_t *mic = enc_data + len;
215
216 BT_DBG("key %s", bt_hex(key, 16));
217 BT_DBG("nonce %s", bt_hex(nonce, 13));
218 BT_DBG("msg (len %zu) %s", len, bt_hex(plaintext, len));
219 BT_DBG("aad_len %zu mic_size %zu", aad_len, mic_size);
220
221 /* Unsupported AAD size */
222 if (aad_len >= 0xff00 || mic_size > 16) {
223 return -EINVAL;
224 }
225
226 ccm_auth(key, nonce, plaintext, len, aad, aad_len, mic, mic_size);
227
228 ccm_crypt(key, nonce, plaintext, enc_data, len);
229
230 return 0;
231 }
232