1 /*
2 * Copyright 2018 Oticon A/S
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include <stdlib.h>
7 #include <stdio.h>
8 #include <stdint.h>
9 #include <string.h>
10 #include "blecrypt.h"
11
print_bytes(const void * data,int data_len)12 static void print_bytes(const void *data, int data_len)
13 {
14 char s[3*data_len + 1];
15 memset(s, 0, 3*data_len + 1);
16 const uint8_t *ip = data;
17 char *op = s;
18 if (data_len > 0)
19 {
20 op += sprintf(op, "%02x", *ip++);
21 while (--data_len > 0)
22 {
23 op += sprintf(op, " %02x", *ip++);
24 }
25 }
26 printf(" %s\n", s);
27 }
28
29 // Calculates session key for encryption/decryption (wrapper for blecrypt_aes_128 function).
30 // Call this once when BLE link is going to be encrypted.
blecrypt_session_key_calc(const uint8_t * skd,const uint8_t * ltk,uint8_t * sk)31 void blecrypt_session_key_calc(
32 // Inputs
33 const uint8_t *skd, // Session key diversifier (SKD_LEN bytes, little-endian)
34 const uint8_t *ltk, // Long (or short) term key (KEY_LEN bytes, little-endian)
35 // Outputs (the pointers themselves are inputs and must point to large enough areas)
36 uint8_t *sk) // Session key (KEY_LEN bytes, BIG-ENDIAN)
37 {
38 uint8_t skd_be[KEY_LEN];
39 uint8_t ltk_be[KEY_LEN];
40
41 // Flip key and plaintext data to big-endian
42 blecrypt_reverse_byte_order(skd, skd_be, KEY_LEN);
43 blecrypt_reverse_byte_order(ltk, ltk_be, KEY_LEN);
44
45 // Calculate session key by encrypting SKD with LTK
46 blecrypt_aes_128(ltk_be, skd_be, sk);
47 }
48
49
50 // Tests session key calculation by calculating session key and checking result against reference.
test_session_key_calc(const uint8_t * skd,const uint8_t * ltk,const uint8_t * expected_sk,uint8_t * sk)51 static void test_session_key_calc(
52 // Inputs
53 const uint8_t *skd,
54 const uint8_t *ltk,
55 const uint8_t *expected_sk, // little-endian here
56 // Outputs (the pointers themselves are inputs and must point to large enough areas)
57 uint8_t *sk) // session key is big-endian for OpenSSL
58 {
59 uint8_t sk_le[KEY_LEN];
60
61 // Calculate session key
62 blecrypt_session_key_calc(skd, ltk, sk);
63
64 // Check results (session key needs to be flipped to little-endian for comparison)
65 blecrypt_reverse_byte_order(sk, sk_le, KEY_LEN);
66 if (memcmp(sk_le, expected_sk, KEY_LEN) != 0)
67 {
68 printf("FAILED: Session key doesn't match reference.\n");
69 exit(1);
70 }
71 printf("PASSED: Verified session key.\n");
72 print_bytes(sk_le, KEY_LEN);
73 }
74
75 // Calculates CCM nonce for packet.
nonce_calc(const uint8_t * iv,uint64_t packet_counter,blecrypt_packet_direction_t packet_direction,uint8_t * ccm_nonce)76 static void nonce_calc(
77 // Inputs
78 const uint8_t *iv, // Initialization vector (IV_LEN bytes, little-endian)
79 uint64_t packet_counter, // 39-bit packet count (in given direction, excl. retransmissions and empty packets) since start of encryption
80 blecrypt_packet_direction_t packet_direction, // Direction of packet
81 // Outputs (the pointers themselves are inputs and must point to large enough areas)
82 uint8_t *ccm_nonce) // Resulting nonce (NONCE_LEN bytes, little-endian)
83 {
84 int i;
85 // Copy 39-bit packet counter into first 5 bytes of nonce and set 40th bit depending on packet
86 // direction
87 for (i = 0; i < NONCE_LEN - IV_LEN - 1; i++)
88 {
89 ccm_nonce[i] = packet_counter & 0xFF;
90 packet_counter >>= 8;
91 }
92 ccm_nonce[i] = (packet_counter & 0x7F) | (packet_direction == MASTER_TO_SLAVE_DIRECTION ? 0x80 : 0);
93 // Copy initialization vector into remaining 8 bytes of nonce
94 memcpy(&ccm_nonce[NONCE_LEN - IV_LEN], iv, IV_LEN);
95 }
96
97
98 // Tests encryption by encrypting 1 packet and checking result against reference.
test_packet_encryption(const uint8_t * unencrypted_packet_payload,const uint8_t * expected_encrypted_packet,blecrypt_packet_direction_t packet_direction,uint64_t packet_counter,const uint8_t * iv,const uint8_t * sk)99 static void test_packet_encryption(
100 // Inputs
101 const uint8_t *unencrypted_packet_payload,
102 const uint8_t *expected_encrypted_packet,
103 blecrypt_packet_direction_t packet_direction,
104 uint64_t packet_counter,
105 const uint8_t *iv,
106 const uint8_t *sk) // session key is big-endian for OpenSSL
107 {
108 // Set up variables
109 uint8_t packet_1st_header_byte = expected_encrypted_packet[0];
110 int packet_payload_and_mic_len = expected_encrypted_packet[1];
111 const uint8_t *expected_encrypted_packet_payload_and_mic = &expected_encrypted_packet[2];
112 int packet_payload_len = packet_payload_and_mic_len - MIC_LEN;
113 uint8_t encrypted_packet_payload_and_mic[255 /*packet_payload_and_mic_len*/]; // Local buffer for encryption output
114
115 uint8_t ccm_nonce[NONCE_LEN];
116 // Calculate nonce
117 nonce_calc(iv, packet_counter, packet_direction, ccm_nonce);
118
119 // Encrypt
120 blecrypt_packet_encrypt(
121 packet_1st_header_byte, packet_payload_len, unencrypted_packet_payload, sk, ccm_nonce,
122 encrypted_packet_payload_and_mic);
123
124 // Check results
125 if (memcmp(encrypted_packet_payload_and_mic, expected_encrypted_packet_payload_and_mic, packet_payload_and_mic_len) != 0)
126 {
127 printf("FAILED: Encrypted packet doesn't match reference.\n");
128 exit(1);
129 }
130 printf("PASSED: Verified encrypted packet payload and MIC.\n");
131 print_bytes(encrypted_packet_payload_and_mic, packet_payload_and_mic_len);
132 }
133
134 // Tests decryption by decrypting 1 packet and checking result against reference.
test_packet_decryption(const uint8_t * encrypted_packet,const uint8_t * expected_decrypted_packet_payload,blecrypt_packet_direction_t packet_direction,uint64_t packet_counter,const uint8_t * iv,const uint8_t * sk,int no_mic)135 static void test_packet_decryption(
136 // Inputs
137 const uint8_t *encrypted_packet,
138 const uint8_t *expected_decrypted_packet_payload,
139 blecrypt_packet_direction_t packet_direction,
140 uint64_t packet_counter,
141 const uint8_t *iv,
142 const uint8_t *sk, // session key is big-endian for OpenSSL
143 int no_mic)
144 {
145 // Set up variables
146 uint8_t packet_1st_header_byte = encrypted_packet[0];
147 int packet_payload_len = encrypted_packet[1] - (no_mic ? 0 : MIC_LEN);
148 const uint8_t *encrypted_packet_payload_and_mic = &encrypted_packet[2];
149 uint8_t decrypted_packet_payload[251 /*packet_payload_len*/]; // Local buffer for decryption output
150 int mic_ok;
151
152 uint8_t ccm_nonce[NONCE_LEN];
153 // Calculate nonce
154 nonce_calc(iv, packet_counter, packet_direction, ccm_nonce);
155
156 // Decrypt
157 mic_ok = blecrypt_packet_decrypt(
158 packet_1st_header_byte, packet_payload_len, encrypted_packet_payload_and_mic, sk, ccm_nonce,
159 no_mic,
160 decrypted_packet_payload);
161
162 // Check results
163 if (!mic_ok)
164 {
165 printf("FAILED: MIC verification failed.\n");
166 exit(1);
167 }
168 if (memcmp(decrypted_packet_payload, expected_decrypted_packet_payload, packet_payload_len) != 0)
169 {
170 printf("FAILED: Decrypted packet doesn't match reference.\n");
171 exit(1);
172 }
173 if (no_mic)
174 {
175 printf("PASSED: Verified decrypted packet payload (MIC not present).\n");
176 }
177 else
178 {
179 printf("PASSED: Verified MIC and decrypted packet payload.\n");
180 }
181 print_bytes(decrypted_packet_payload, packet_payload_len);
182 }
183
184 ///////////////////////////////////////////////////////////////////////////////
185 // BLE sample data from BT Core v4.2 vol 6 part C section 1
186 ///////////////////////////////////////////////////////////////////////////////
187
188 // LTK (16 bytes little-endian) - slave's long term key
189 static const uint8_t ref_ltk[KEY_LEN] = {
190 0xbf, 0x01, 0xfb, 0x9d, 0x4e, 0xf3, 0xbc, 0x36, 0xd8, 0x74, 0xf5, 0x39, 0x41, 0x38, 0x68, 0x4c
191 };
192
193 // SKDm (8 bytes little-endian) - master's part of session key diversifier
194 static const uint8_t ref_skd_m[SKD_LEN/2] = {
195 0x13, 0x02, 0xf1, 0xe0, 0xdf, 0xce, 0xbd, 0xac
196 };
197
198 // IVm (4 bytes little-endian) - master's part of initialization vector
199 static const uint8_t ref_iv_m[IV_LEN/2] = {
200 0x24, 0xab, 0xdc, 0xba
201 };
202
203 // SKDs (8 bytes little-endian) - slave's part of session key diversifier
204 static const uint8_t ref_skd_s[SKD_LEN/2] = {
205 0x79, 0x68, 0x57, 0x46, 0x35, 0x24, 0x13, 0x02
206 };
207
208 // IVs (4 bytes little-endian) - slave's part of initialization vector
209 static const uint8_t ref_iv_s[IV_LEN/2] = {
210 0xbe, 0xba, 0xaf, 0xde
211 };
212
213 // SK (16 bytes little-endian) - session key (this is the CCM key used to encrypt BLE packets)
214 static const uint8_t ref_sk[KEY_LEN] = {
215 0x66, 0xc6, 0xc2, 0x27, 0x8e, 0x3b, 0x8e, 0x05, 0x3e, 0x7e, 0xa3, 0x26, 0x52, 0x1b, 0xad, 0x99
216 };
217
218 // Packets
219
220 // LL_START_ENC_RSP1 (master -> slave)
221 static const uint8_t packet0_encrypted[] = {
222 0x0F, 0x05, 0x9f, 0xcd, 0xa7, 0xf4, 0x48
223 };
224 static const uint8_t packet0_payload_unencrypted[] = {
225 0x06
226 };
227
228 // LL_START_ENC_RSP2 (slave -> master)
229 static const uint8_t packet1_encrypted[] = {
230 0x07, 0x05, 0xa3, 0x4c, 0x13, 0xa4, 0x15
231 };
232 static const uint8_t packet1_payload_unencrypted[] = {
233 0x06
234 };
235
236 // LL_DATA1 (master -> slave)
237 static const uint8_t packet2_encrypted[] = {
238 0x0e, 0x1f, 0x7a, 0x70, 0xd6, 0x64, 0x15, 0x22, 0x6d, 0xf2, 0x6b, 0x17, 0x83, 0x9a, 0x06, 0x04, 0x05, 0x59, 0x6b, 0xd6, 0x56, 0x4f, 0x79, 0x6b, 0x5b, 0x9c, 0xe6, 0xff, 0x32, 0xf7, 0x5a, 0x6d, 0x33
239 };
240 static const uint8_t packet2_payload_unencrypted[] = {
241 0x17, 0x00, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30
242 };
243
244 // LL_DATA2 (slave -> master)
245 static const uint8_t packet3_encrypted[] = {
246 0x06, 0x1f, 0xf3, 0x88, 0x81, 0xe7, 0xbd, 0x94, 0xc9, 0xc3, 0x69, 0xb9, 0xa6, 0x68, 0x46, 0xdd, 0x47, 0x86, 0xaa, 0x8c, 0x39, 0xce, 0x54, 0x0d, 0x0d, 0xae, 0x3a, 0xdc, 0xdf, 0x89, 0xb9, 0x60, 0x88
247 };
248 static const uint8_t packet3_payload_unencrypted[] = {
249 0x17, 0x00, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51
250 };
251
252 ///////////////////////////////////////////////////////////////////////////////
253 // End of BLE sample data
254 ///////////////////////////////////////////////////////////////////////////////
255
256 ///////////////////////////////////////////////////////////////////////////////
257 // MIC-less test data (copy of BLE sample data with MIC removed)
258 ///////////////////////////////////////////////////////////////////////////////
259
260 // LL_DATA1 (master -> slave) with no MIC
261 static const uint8_t packet2_encrypted_no_mic[] = {
262 0x0e, 0x1b, 0x7a, 0x70, 0xd6, 0x64, 0x15, 0x22, 0x6d, 0xf2, 0x6b, 0x17, 0x83, 0x9a, 0x06, 0x04, 0x05, 0x59, 0x6b, 0xd6, 0x56, 0x4f, 0x79, 0x6b, 0x5b, 0x9c, 0xe6, 0xff, 0x32
263 };
264
265 ///////////////////////////////////////////////////////////////////////////////
266 // End of MIC-less test data
267 ///////////////////////////////////////////////////////////////////////////////
268
269
270 // Values of MIC presence flag for decryption
271 #define HAS_MIC 0
272 #define HAS_NO_MIC 1
273
main(int argc,char * argv[])274 int main(int argc, char *argv[])
275 {
276 // In reality both the master and slave devices have copies of both the master and slave packet
277 // counters, but the counter values should always be the same in both devices (as soon as
278 // transmissions have been acknowledged), so for this test bench we need only 1 copy of the 2
279 // counters
280 uint64_t master_packet_counter = 0;
281 uint64_t slave_packet_counter = 0;
282
283 // SKD - session key diversifier
284 uint8_t skd[SKD_LEN];
285 // IV - initialization vector
286 uint8_t iv[IV_LEN];
287 // SK - session key (this is the CCM key used to encrypt BLE packets)
288 uint8_t sk[KEY_LEN]; // sk is big-endian for OpenSSL
289
290 // Calculate SKD by concatenating SKDm and SKDs (master and slave contributions)
291 memcpy(skd, ref_skd_m, SKD_LEN/2);
292 memcpy(skd + SKD_LEN/2, ref_skd_s, SKD_LEN/2);
293
294 // Calculate IV by concatenating IVm and IVs (master and slave contributions)
295 memcpy(iv, ref_iv_m, IV_LEN/2);
296 memcpy(iv + IV_LEN/2, ref_iv_s, IV_LEN/2);
297
298 // Calculate session key, and check results
299 test_session_key_calc(skd, ref_ltk, ref_sk, sk);
300
301 // Encrypt and decrypt packets, and check results
302 test_packet_encryption(packet0_payload_unencrypted, packet0_encrypted, MASTER_TO_SLAVE_DIRECTION, master_packet_counter, iv, sk);
303 test_packet_decryption(packet0_encrypted, packet0_payload_unencrypted, MASTER_TO_SLAVE_DIRECTION, master_packet_counter, iv, sk, HAS_MIC);
304 master_packet_counter++;
305 test_packet_encryption(packet1_payload_unencrypted, packet1_encrypted, SLAVE_TO_MASTER_DIRECTION, slave_packet_counter, iv, sk);
306 test_packet_decryption(packet1_encrypted, packet1_payload_unencrypted, SLAVE_TO_MASTER_DIRECTION, slave_packet_counter, iv, sk, HAS_MIC);
307 slave_packet_counter++;
308 test_packet_encryption(packet2_payload_unencrypted, packet2_encrypted, MASTER_TO_SLAVE_DIRECTION, master_packet_counter, iv, sk);
309 test_packet_decryption(packet2_encrypted, packet2_payload_unencrypted, MASTER_TO_SLAVE_DIRECTION, master_packet_counter, iv, sk, HAS_MIC);
310 // Non-standard MIC-less encryption mode
311 test_packet_decryption(packet2_encrypted_no_mic, packet2_payload_unencrypted, MASTER_TO_SLAVE_DIRECTION, master_packet_counter, iv, sk, HAS_NO_MIC);
312 master_packet_counter++;
313 test_packet_encryption(packet3_payload_unencrypted, packet3_encrypted, SLAVE_TO_MASTER_DIRECTION, slave_packet_counter, iv, sk);
314 test_packet_decryption(packet3_encrypted, packet3_payload_unencrypted, SLAVE_TO_MASTER_DIRECTION, slave_packet_counter, iv, sk, HAS_MIC);
315 slave_packet_counter++;
316
317 printf("All tests PASSED!\n");
318 return 0;
319 }
320