• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2015 Intel Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 /* These functions are adapted from the Intel Zephyr BLE security manager
18  * code.
19  */
20 
21 #include "syscfg/syscfg.h"
22 #include "nimble/nimble_opt.h"
23 #include "securec.h"
24 
25 #if NIMBLE_BLE_SM
26 
27 #include "nimble/ble.h"
28 #include "ble_hs_priv.h"
29 #include "tinycrypt/aes.h"
30 #include "tinycrypt/constants.h"
31 #include "tinycrypt/utils.h"
32 
33 #if MYNEWT_VAL(BLE_SM_SC)
34 #include "tinycrypt/cmac_mode.h"
35 #include "tinycrypt/ecc_dh.h"
36 #if MYNEWT_VAL(TRNG)
37 #include "trng/trng.h"
38 #endif
39 #endif
40 
41 #if MYNEWT_VAL(BLE_SM_SC) && MYNEWT_VAL(TRNG)
42 static struct trng_dev *g_trng;
43 #endif
44 
ble_sm_alg_xor_128(const uint8_t * p,const uint8_t * q,uint8_t * r)45 static void ble_sm_alg_xor_128(const uint8_t *p, const uint8_t *q, uint8_t *r)
46 {
47     int i;
48 
49     for (i = 0; i < 16; i++) { // 16:loop cap
50         r[i] = p[i] ^ q[i];
51     }
52 }
53 
ble_sm_alg_encrypt(const uint8_t * key,const uint8_t * plaintext,uint8_t * enc_data)54 static int ble_sm_alg_encrypt(const uint8_t *key, const uint8_t *plaintext, uint8_t *enc_data)
55 {
56     struct tc_aes_key_sched_struct s;
57     uint8_t tmp[16];
58     swap_buf(tmp, key, 16); // 16:len
59 
60     if (tc_aes128_set_encrypt_key(&s, tmp) == TC_CRYPTO_FAIL) {
61         return BLE_HS_EUNKNOWN;
62     }
63 
64     swap_buf(tmp, plaintext, 16); // 16:len
65 
66     if (tc_aes_encrypt(enc_data, tmp, &s) == TC_CRYPTO_FAIL) {
67         return BLE_HS_EUNKNOWN;
68     }
69 
70     swap_in_place(enc_data, 16); // 16:len
71     return 0;
72 }
73 
ble_sm_alg_s1(const uint8_t * k,const uint8_t * r1,const uint8_t * r2,uint8_t * out)74 int ble_sm_alg_s1(const uint8_t *k, const uint8_t *r1, const uint8_t *r2, uint8_t *out)
75 {
76     int rc;
77     /* The most significant 64-bits of r1 are discarded to generate
78      * r1' and the most significant 64-bits of r2 are discarded to
79      * generate r2'.
80      * r1' is concatenated with r2' to generate r' which is used as
81      * the 128-bit input parameter plaintextData to security function e:
82      *
83      *    r' = r1' || r2'
84      */
85     memcpy_s(out, sizeof(*out), r2, 8); // 8:size
86     memcpy_s(out + 8, sizeof(out + 8), r1, 8); // 8:size
87     rc = ble_sm_alg_encrypt(k, out, out);
88     if (rc != 0) {
89         return rc;
90     }
91 
92     BLE_HS_LOG(DEBUG, "ble_sm_alg_s1()\n    k=");
93     ble_hs_log_flat_buf(k, 16); // 16:len
94     BLE_HS_LOG(DEBUG, "\n    r1=");
95     ble_hs_log_flat_buf(r1, 16); // 16:len
96     BLE_HS_LOG(DEBUG, "\n    r2=");
97     ble_hs_log_flat_buf(r2, 16); // 16:len
98     BLE_HS_LOG(DEBUG, "\n    out=");
99     ble_hs_log_flat_buf(out, 16); // 16:len
100     BLE_HS_LOG(DEBUG, "\n");
101     return 0;
102 }
103 
ble_sm_alg_c1(const uint8_t * k,const uint8_t * r,const uint8_t * preq,const uint8_t * pres,uint8_t iat,uint8_t rat,const uint8_t * ia,const uint8_t * ra,uint8_t * out_enc_data)104 int ble_sm_alg_c1(const uint8_t *k, const uint8_t *r,
105                   const uint8_t *preq, const uint8_t *pres,
106                   uint8_t iat, uint8_t rat,
107                   const uint8_t *ia, const uint8_t *ra,
108                   uint8_t *out_enc_data)
109 {
110     uint8_t p1[16], p2[16];
111     int rc;
112     BLE_HS_LOG(DEBUG, "ble_sm_alg_c1()\n    k=");
113     ble_hs_log_flat_buf(k, 16); // 16:len
114     BLE_HS_LOG(DEBUG, "\n    r=");
115     ble_hs_log_flat_buf(r, 16); // 16:len
116     BLE_HS_LOG(DEBUG, "\n    iat=%d rat=%d", iat, rat);
117     BLE_HS_LOG(DEBUG, "\n    ia=");
118     ble_hs_log_flat_buf(ia, 6); // 6:len
119     BLE_HS_LOG(DEBUG, "\n    ra=");
120     ble_hs_log_flat_buf(ra, 6); // 6:len
121     BLE_HS_LOG(DEBUG, "\n    preq=");
122     ble_hs_log_flat_buf(preq, 7); // 7:len
123     BLE_HS_LOG(DEBUG, "\n    pres=");
124     ble_hs_log_flat_buf(pres, 7); // 7:len
125     /* pres, preq, rat and iat are concatenated to generate p1 */
126     p1[0] = iat;
127     p1[1] = rat;
128     memcpy_s(p1 + 2, sizeof(p1 + 2), preq, 7); // 2:byte alignment, 7:len
129     memcpy_s(p1 + 9, sizeof(p1 + 9), pres, 7); // 9:byte alignment, 7:len
130     BLE_HS_LOG(DEBUG, "\n    p1=");
131     ble_hs_log_flat_buf(p1, sizeof p1);
132     /* Using out_enc_data as temporary output buffer */
133     ble_sm_alg_xor_128(r, p1, out_enc_data);
134     rc = ble_sm_alg_encrypt(k, out_enc_data, out_enc_data);
135     if (rc != 0) {
136         rc = BLE_HS_EUNKNOWN;
137         goto done;
138     }
139 
140     /* ra is concatenated with ia and padding to generate p2 */
141     memcpy_s(p2, sizeof(p2), ra, 6); // 6:len
142     memcpy_s(p2 + 6, sizeof(p2 + 6), ia, 6); // 6:byte alignment, 6:len
143     memset_s(p2 + 12, sizeof(p2 + 12), 0, 4); // 12:byte alignment, 4:len
144     BLE_HS_LOG(DEBUG, "\n    p2=");
145     ble_hs_log_flat_buf(p2, sizeof p2);
146     ble_sm_alg_xor_128(out_enc_data, p2, out_enc_data);
147     rc = ble_sm_alg_encrypt(k, out_enc_data, out_enc_data);
148     if (rc != 0) {
149         rc = BLE_HS_EUNKNOWN;
150         goto done;
151     }
152 
153     BLE_HS_LOG(DEBUG, "\n    out_enc_data=");
154     ble_hs_log_flat_buf(out_enc_data, 16); // 16:len
155     rc = 0;
156 done:
157     BLE_HS_LOG(DEBUG, "\n    rc=%d\n", rc);
158     return rc;
159 }
160 
161 #if MYNEWT_VAL(BLE_SM_SC)
162 
ble_sm_alg_log_buf(const char * name,const uint8_t * buf,int len)163 static void ble_sm_alg_log_buf(const char *name, const uint8_t *buf, int len)
164 {
165     BLE_HS_LOG(DEBUG, "    %s=", name);
166     ble_hs_log_flat_buf(buf, len);
167     BLE_HS_LOG(DEBUG, "\n");
168 }
169 
170 /**
171  * Cypher based Message Authentication Code (CMAC) with AES 128 bit
172  *
173  * @param key                   128-bit key.
174  * @param in                    Message to be authenticated.
175  * @param len                   Length of the message in octets.
176  * @param out                   Output; message authentication code.
177  */
ble_sm_alg_aes_cmac(const uint8_t * key,const uint8_t * in,size_t len,uint8_t * out)178 static int ble_sm_alg_aes_cmac(const uint8_t *key, const uint8_t *in, size_t len, uint8_t *out)
179 {
180     struct tc_aes_key_sched_struct sched;
181     struct tc_cmac_struct state;
182 
183     if (tc_cmac_setup(&state, key, &sched) == TC_CRYPTO_FAIL) {
184         return BLE_HS_EUNKNOWN;
185     }
186 
187     if (tc_cmac_update(&state, in, len) == TC_CRYPTO_FAIL) {
188         return BLE_HS_EUNKNOWN;
189     }
190 
191     if (tc_cmac_final(out, &state) == TC_CRYPTO_FAIL) {
192         return BLE_HS_EUNKNOWN;
193     }
194 
195     return 0;
196 }
197 
ble_sm_alg_f4(const uint8_t * u,const uint8_t * v,const uint8_t * x,uint8_t z,uint8_t * out_enc_data)198 int ble_sm_alg_f4(const uint8_t *u, const uint8_t *v, const uint8_t *x, uint8_t z, uint8_t *out_enc_data)
199 {
200     uint8_t xs[16];
201     uint8_t m[65];
202     int rc;
203     BLE_HS_LOG(DEBUG, "ble_sm_alg_f4()\n    u=");
204     ble_hs_log_flat_buf(u, 32); // 32:len
205     BLE_HS_LOG(DEBUG, "\n    v=");
206     ble_hs_log_flat_buf(v, 32); // 32:len
207     BLE_HS_LOG(DEBUG, "\n    x=");
208     ble_hs_log_flat_buf(x, 16); // 16:len
209     BLE_HS_LOG(DEBUG, "\n    z=0x%02x\n", z);
210     /*
211      * U, V and Z are concatenated and used as input m to the function
212      * AES-CMAC and X is used as the key k.
213      *
214      * Core Spec 4.2 Vol 3 Part H 2.2.5
215      *
216      * note:
217      * ble_sm_alg_aes_cmac uses BE data; ble_sm_alg_f4 accepts LE so we swap.
218      */
219     swap_buf(m, u, 32); // 32:len
220     swap_buf(m + 32, v, 32); // 32:len
221     m[64] = z;
222     swap_buf(xs, x, 16); // 16:len
223     rc = ble_sm_alg_aes_cmac(xs, m, sizeof(m), out_enc_data);
224     if (rc != 0) {
225         return BLE_HS_EUNKNOWN;
226     }
227 
228     swap_in_place(out_enc_data, 16); // 16:len
229     BLE_HS_LOG(DEBUG, "    out_enc_data=");
230     ble_hs_log_flat_buf(out_enc_data, 16); // 16:len
231     BLE_HS_LOG(DEBUG, "\n");
232     return 0;
233 }
234 
ble_sm_alg_f5(const uint8_t * w,const uint8_t * n1,const uint8_t * n2,uint8_t a1t,const uint8_t * a1,uint8_t a2t,const uint8_t * a2,uint8_t * mackey,uint8_t * ltk)235 int ble_sm_alg_f5(const uint8_t *w, const uint8_t *n1, const uint8_t *n2,
236                   uint8_t a1t, const uint8_t *a1, uint8_t a2t, const uint8_t *a2,
237                   uint8_t *mackey, uint8_t *ltk)
238 {
239     static const uint8_t salt[16] = { 0x6c, 0x88, 0x83, 0x91, 0xaa, 0xf5,
240                                       0xa5, 0x38, 0x60, 0x37, 0x0b, 0xdb,
241                                       0x5a, 0x60, 0x83, 0xbe
242                                     };
243     uint8_t m[53] = {
244         0x00, /* counter */
245         0x62, 0x74, 0x6c, 0x65, /* keyID */
246         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* n1 */
247         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
248         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 2 */
249         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
250         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* a1 */
251         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* a2 */
252         0x01, 0x00 /* length */
253     };
254     uint8_t ws[32];
255     uint8_t t[16];
256     int rc;
257     BLE_HS_LOG(DEBUG, "ble_sm_alg_f5()\n");
258     ble_sm_alg_log_buf("w", w, 32); // 32:len
259     ble_sm_alg_log_buf("n1", n1, 16); // 16:len
260     ble_sm_alg_log_buf("n2", n2, 16); // 16:len
261     swap_buf(ws, w, 32); // 32:len
262     rc = ble_sm_alg_aes_cmac(salt, ws, 32, t); // 32:len
263     if (rc != 0) {
264         return BLE_HS_EUNKNOWN;
265     }
266 
267     ble_sm_alg_log_buf("t", t, 16); // 16:len
268     swap_buf(m + 5, n1, 16); // 16:len
269     swap_buf(m + 21, n2, 16); // 16:len
270     m[37] = a1t; // 37:array element
271     swap_buf(m + 38, a1, 6); // 6:len, 38:byte alignment
272     m[44] = a2t; // 44:array element
273     swap_buf(m + 45, a2, 6); // 6:len, 45:byte alignment
274     rc = ble_sm_alg_aes_cmac(t, m, sizeof(m), mackey);
275     if (rc != 0) {
276         return BLE_HS_EUNKNOWN;
277     }
278 
279     ble_sm_alg_log_buf("mackey", mackey, 16); // 16:len
280     swap_in_place(mackey, 16); // 16:len
281     /* Counter for ltk is 1. */
282     m[0] = 0x01;
283     rc = ble_sm_alg_aes_cmac(t, m, sizeof(m), ltk);
284     if (rc != 0) {
285         return BLE_HS_EUNKNOWN;
286     }
287 
288     ble_sm_alg_log_buf("ltk", ltk, 16); // 16:len
289     swap_in_place(ltk, 16); // 16:len
290     return 0;
291 }
292 
ble_sm_alg_f6(const uint8_t * w,const uint8_t * n1,const uint8_t * n2,const uint8_t * r,const uint8_t * iocap,uint8_t a1t,const uint8_t * a1,uint8_t a2t,const uint8_t * a2,uint8_t * check)293 int ble_sm_alg_f6(const uint8_t *w, const uint8_t *n1, const uint8_t *n2,
294                   const uint8_t *r, const uint8_t *iocap, uint8_t a1t,
295                   const uint8_t *a1, uint8_t a2t, const uint8_t *a2,
296                   uint8_t *check)
297 {
298     uint8_t ws[16];
299     uint8_t m[65];
300     int rc;
301     BLE_HS_LOG(DEBUG, "ble_sm_alg_f6()\n");
302     ble_sm_alg_log_buf("w", w, 16); // 16:len
303     ble_sm_alg_log_buf("n1", n1, 16); // 16:len
304     ble_sm_alg_log_buf("n2", n2, 16); // 16:len
305     ble_sm_alg_log_buf("r", r, 16); // 16:len
306     ble_sm_alg_log_buf("iocap", iocap, 3); // 3:len
307     ble_sm_alg_log_buf("a1t", &a1t, 1);
308     ble_sm_alg_log_buf("a1", a1, 6); // 6:len
309     ble_sm_alg_log_buf("a2t", &a2t, 1);
310     ble_sm_alg_log_buf("a2", a2, 6); // 6:len
311     swap_buf(m, n1, 16); // 16:len
312     swap_buf(m + 16, n2, 16); // 16:len, 16:byte alignment
313     swap_buf(m + 32, r, 16); // 16:len, 32:byte alignment
314     swap_buf(m + 48, iocap, 3); // 3:len, 48:byte alignment
315     m[51] = a1t; // 51:array element
316     memcpy_s(m + 52, sizeof(m + 52), a1, 6); // 6:len, 52:byte alignment
317     swap_buf(m + 52, a1, 6); // 6:len, 52:byte alignment
318     m[58] = a2t; // 58:array element
319     memcpy_s(m + 59, sizeof(m + 59), a2, 6); // 6:len, 59:byte alignment
320     swap_buf(m + 59, a2, 6); // 6:len, 59:byte alignment
321     swap_buf(ws, w, 16); // 16:len
322     rc = ble_sm_alg_aes_cmac(ws, m, sizeof(m), check);
323     if (rc != 0) {
324         return BLE_HS_EUNKNOWN;
325     }
326 
327     ble_sm_alg_log_buf("res", check, 16); // 16:len
328     swap_in_place(check, 16); // 16:len
329     return 0;
330 }
331 
ble_sm_alg_g2(const uint8_t * u,const uint8_t * v,const uint8_t * x,const uint8_t * y,uint32_t * passkey)332 int ble_sm_alg_g2(const uint8_t *u, const uint8_t *v, const uint8_t *x, const uint8_t *y, uint32_t *passkey)
333 {
334     uint8_t m[80], xs[16];
335     int rc;
336     BLE_HS_LOG(DEBUG, "ble_sm_alg_g2()\n");
337     ble_sm_alg_log_buf("u", u, 32); // 32:len
338     ble_sm_alg_log_buf("v", v, 32); // 32:len
339     ble_sm_alg_log_buf("x", x, 16); // 16:len
340     ble_sm_alg_log_buf("y", y, 16); // 16:len
341     swap_buf(m, u, 32); // 16:len
342     swap_buf(m + 32, v, 32); // 6:len, 32:byte alignment
343     swap_buf(m + 64, y, 16); // 6:len, 64:byte alignment
344     swap_buf(xs, x, 16); // 16:len
345     /* reuse xs (key) as buffer for result */
346     rc = ble_sm_alg_aes_cmac(xs, m, sizeof(m), xs);
347     if (rc != 0) {
348         return BLE_HS_EUNKNOWN;
349     }
350 
351     ble_sm_alg_log_buf("res", xs, 16); // 16:len
352     *passkey = get_be32(xs + 12) % 1000000; // 12:byte alignment
353     BLE_HS_LOG(DEBUG, "    passkey=%u\n", *passkey);
354     return 0;
355 }
356 
ble_sm_alg_gen_dhkey(const uint8_t * peer_pub_key_x,const uint8_t * peer_pub_key_y,const uint8_t * our_priv_key,uint8_t * out_dhkey)357 int ble_sm_alg_gen_dhkey(const uint8_t *peer_pub_key_x, const uint8_t *peer_pub_key_y,
358                          const uint8_t *our_priv_key, uint8_t *out_dhkey)
359 {
360     uint8_t dh[32];
361     uint8_t pk[64];
362     uint8_t priv[32];
363     int rc;
364     swap_buf(pk, peer_pub_key_x, 32); // 32:len
365     swap_buf(&pk[32], peer_pub_key_y, 32); // 32:len
366     swap_buf(priv, our_priv_key, 32); // 32:len
367 
368     if (uECC_valid_public_key(pk, &curve_secp256r1) < 0) {
369         return BLE_HS_EUNKNOWN;
370     }
371 
372     rc = uECC_shared_secret(pk, priv, dh, &curve_secp256r1);
373     if (rc == TC_CRYPTO_FAIL) {
374         return BLE_HS_EUNKNOWN;
375     }
376 
377     swap_buf(out_dhkey, dh, 32); // 32:len
378     return 0;
379 }
380 
381 /* based on Core Specification 4.2 Vol 3. Part H 2.3.5.6.1 */
382 static const uint8_t ble_sm_alg_dbg_priv_key[32] = {
383     0x3f, 0x49, 0xf6, 0xd4, 0xa3, 0xc5, 0x5f, 0x38, 0x74, 0xc9, 0xb3, 0xe3,
384     0xd2, 0x10, 0x3f, 0x50, 0x4a, 0xff, 0x60, 0x7b, 0xeb, 0x40, 0xb7, 0x99,
385     0x58, 0x99, 0xb8, 0xa6, 0xcd, 0x3c, 0x1a, 0xbd
386 };
387 
388 #if MYNEWT_VAL(BLE_SM_SC_DEBUG_KEYS)
389 static const uint8_t ble_sm_alg_dbg_pub_key[64] = {
390     /* X */
391     0x20, 0xb0, 0x03, 0xd2, 0xf2, 0x97, 0xbe, 0x2c, 0x5e, 0x2c, 0x83, 0xa7,
392     0xe9, 0xf9, 0xa5, 0xb9, 0xef, 0xf4, 0x91, 0x11, 0xac, 0xf4, 0xfd, 0xdb,
393     0xcc, 0x03, 0x01, 0x48, 0x0e, 0x35, 0x9d, 0xe6,
394     /* Y */
395     0xdc, 0x80, 0x9c, 0x49, 0x65, 0x2a, 0xeb, 0x6d, 0x63, 0x32, 0x9a, 0xbf,
396     0x5a, 0x52, 0x15, 0x5c, 0x76, 0x63, 0x45, 0xc2, 0x8f, 0xed, 0x30, 0x24,
397     0x74, 0x1c, 0x8e, 0xd0, 0x15, 0x89, 0xd2, 0x8b,
398 };
399 #endif
400 
401 /**
402  * pub: 64 bytes
403  * priv: 32 bytes
404  */
ble_sm_alg_gen_key_pair(uint8_t * pub,uint8_t * priv)405 int ble_sm_alg_gen_key_pair(uint8_t *pub, uint8_t *priv)
406 {
407 #if MYNEWT_VAL(BLE_SM_SC_DEBUG_KEYS)
408     swap_buf(pub, ble_sm_alg_dbg_pub_key, 32);
409     swap_buf(&pub[32], &ble_sm_alg_dbg_pub_key[32], 32);
410     swap_buf(priv, ble_sm_alg_dbg_priv_key, 32);
411 #else
412     uint8_t pk[64];
413 
414     do {
415         if (uECC_make_key(pk, priv, &curve_secp256r1) != TC_CRYPTO_SUCCESS) {
416             return BLE_HS_EUNKNOWN;
417         }
418 
419         /* Make sure generated key isn't debug key. */
420     } while (memcmp(priv, ble_sm_alg_dbg_priv_key, 32) == 0); // 16:size
421 
422     swap_buf(pub, pk, 32); // 32:len
423     swap_buf(&pub[32], &pk[32], 32); // 32:len
424     swap_in_place(priv, 32); // 32:len
425 #endif
426     return 0;
427 }
428 
429 /* used by uECC to get random data */
ble_sm_alg_rand(uint8_t * dst,unsigned int size)430 static int ble_sm_alg_rand(uint8_t *dst, unsigned int size)
431 {
432 #if MYNEWT_VAL(TRNG)
433     size_t num;
434 
435     if (!g_trng) {
436         g_trng = (struct trng_dev *)os_dev_open("trng", OS_WAIT_FOREVER, NULL);
437         assert(g_trng);
438     }
439 
440     while (size) {
441         num = trng_read(g_trng, dst, size);
442         dst += num;
443         size -= num;
444     }
445 
446 #else
447 
448     if (ble_hs_hci_util_rand(dst, size)) {
449         return 0;
450     }
451 
452 #endif
453     return 1;
454 }
455 
ble_sm_alg_ecc_init(void)456 void ble_sm_alg_ecc_init(void)
457 {
458     uECC_set_rng(ble_sm_alg_rand);
459 }
460 
461 #endif
462 #endif