1 /* Copyright (c) 2023 Nordic Semiconductor ASA
2  * SPDX-License-Identifier: Apache-2.0
3  */
4 
5 #include <zephyr/bluetooth/ead.h>
6 #include <zephyr/bluetooth/crypto.h>
7 #include <zephyr/bluetooth/bluetooth.h>
8 
9 #include <stddef.h>
10 #include <stdint.h>
11 #include <string.h>
12 
13 #include <zephyr/sys/check.h>
14 
15 #include <zephyr/logging/log.h>
16 
17 /** nonce size in bytes */
18 #define BT_EAD_NONCE_SIZE 13
19 
20 /* This value is used to set the directionBit of the CCM  nonce to the MSB of the Randomizer field
21  * (see Supplement to the Bluetooth Core   Specification v11, Part A 1.23.3)
22  */
23 #define BT_EAD_RANDOMIZER_DIRECTION_BIT 7
24 
25 /** Additional Authenticated Data size in bytes */
26 #define BT_EAD_AAD_SIZE 1
27 
28 /* Fixed value used for the Additional Authenticated Data (see Supplement to the Bluetooth Core
29  * Specification v11, Part A 1.23.3)
30  */
31 static uint8_t bt_ead_aad[] = {0xEA};
32 BUILD_ASSERT(sizeof(bt_ead_aad) == BT_EAD_AAD_SIZE);
33 
34 LOG_MODULE_REGISTER(bt_encrypted_ad_data, CONFIG_BT_EAD_LOG_LEVEL);
35 
bt_ead_generate_randomizer(uint8_t randomizer[BT_EAD_RANDOMIZER_SIZE])36 static int bt_ead_generate_randomizer(uint8_t randomizer[BT_EAD_RANDOMIZER_SIZE])
37 {
38 	int err;
39 
40 	err = bt_rand(randomizer, BT_EAD_RANDOMIZER_SIZE);
41 
42 	if (err != 0) {
43 		return -ECANCELED;
44 	}
45 
46 	/* From Supplement to the Bluetooth Core Specification v11, Part A 1.23.3: The directionBit
47 	 * of the CCM nonce shall be set to the most significant bit of the Randomizer field.
48 	 */
49 	randomizer[4] |= 1 << BT_EAD_RANDOMIZER_DIRECTION_BIT;
50 
51 	return 0;
52 }
53 
bt_ead_generate_nonce(const uint8_t iv[BT_EAD_IV_SIZE],const uint8_t randomizer[BT_EAD_RANDOMIZER_SIZE],uint8_t * nonce)54 static int bt_ead_generate_nonce(const uint8_t iv[BT_EAD_IV_SIZE],
55 				 const uint8_t randomizer[BT_EAD_RANDOMIZER_SIZE], uint8_t *nonce)
56 {
57 	uint8_t new_randomizer[BT_EAD_RANDOMIZER_SIZE];
58 
59 	if (randomizer == NULL) {
60 		int err;
61 
62 		err = bt_ead_generate_randomizer(new_randomizer);
63 
64 		if (err != 0) {
65 			LOG_DBG("Failed to generate Randomizer");
66 			return -ECANCELED;
67 		}
68 
69 		randomizer = new_randomizer;
70 	}
71 
72 	memcpy(&nonce[0], randomizer, BT_EAD_RANDOMIZER_SIZE);
73 	memcpy(&nonce[BT_EAD_RANDOMIZER_SIZE], iv, BT_EAD_IV_SIZE);
74 
75 	return 0;
76 }
77 
ead_encrypt(const uint8_t session_key[BT_EAD_KEY_SIZE],const uint8_t iv[BT_EAD_IV_SIZE],const uint8_t randomizer[BT_EAD_RANDOMIZER_SIZE],const uint8_t * payload,size_t payload_size,uint8_t * encrypted_payload)78 static int ead_encrypt(const uint8_t session_key[BT_EAD_KEY_SIZE], const uint8_t iv[BT_EAD_IV_SIZE],
79 		       const uint8_t randomizer[BT_EAD_RANDOMIZER_SIZE], const uint8_t *payload,
80 		       size_t payload_size, uint8_t *encrypted_payload)
81 {
82 	int err;
83 	uint8_t nonce[BT_EAD_NONCE_SIZE];
84 	size_t ead_size = BT_EAD_RANDOMIZER_SIZE + payload_size + BT_EAD_MIC_SIZE;
85 
86 	err = bt_ead_generate_nonce(iv, randomizer, nonce);
87 	if (err != 0) {
88 		return -ECANCELED;
89 	}
90 
91 	memcpy(encrypted_payload, nonce, BT_EAD_RANDOMIZER_SIZE);
92 
93 	err = bt_ccm_encrypt(session_key, nonce, payload, payload_size, bt_ead_aad, BT_EAD_AAD_SIZE,
94 			     &encrypted_payload[BT_EAD_RANDOMIZER_SIZE], BT_EAD_MIC_SIZE);
95 	if (err != 0) {
96 		LOG_DBG("Failed to encrypt the payload (bt_ccm_encrypt err %d)", err);
97 		return -EIO;
98 	}
99 
100 	LOG_HEXDUMP_DBG(encrypted_payload, ead_size, "Encrypted Data: ");
101 
102 	return 0;
103 }
104 
bt_ead_encrypt(const uint8_t session_key[BT_EAD_KEY_SIZE],const uint8_t iv[BT_EAD_IV_SIZE],const uint8_t * payload,size_t payload_size,uint8_t * encrypted_payload)105 int bt_ead_encrypt(const uint8_t session_key[BT_EAD_KEY_SIZE], const uint8_t iv[BT_EAD_IV_SIZE],
106 		   const uint8_t *payload, size_t payload_size, uint8_t *encrypted_payload)
107 {
108 	CHECKIF(session_key == NULL) {
109 		LOG_DBG("session_key is NULL");
110 		return -EINVAL;
111 	}
112 
113 	CHECKIF(iv == NULL) {
114 		LOG_DBG("iv is NULL");
115 		return -EINVAL;
116 	}
117 
118 	CHECKIF(payload == NULL) {
119 		LOG_DBG("payload is NULL");
120 		return -EINVAL;
121 	}
122 
123 	CHECKIF(encrypted_payload == NULL) {
124 		LOG_DBG("encrypted_payload is NULL");
125 		return -EINVAL;
126 	}
127 
128 	if (payload_size == 0) {
129 		LOG_WRN("payload_size is set to 0. The encrypted result will only contain the "
130 			"Randomizer and the MIC.");
131 	}
132 
133 	return ead_encrypt(session_key, iv, NULL, payload, payload_size, encrypted_payload);
134 }
135 
136 #if defined(CONFIG_BT_TESTING)
137 
bt_test_ead_encrypt(const uint8_t session_key[BT_EAD_KEY_SIZE],const uint8_t iv[BT_EAD_IV_SIZE],const uint8_t randomizer[BT_EAD_RANDOMIZER_SIZE],const uint8_t * payload,size_t payload_size,uint8_t * encrypted_payload)138 int bt_test_ead_encrypt(const uint8_t session_key[BT_EAD_KEY_SIZE],
139 			const uint8_t iv[BT_EAD_IV_SIZE],
140 			const uint8_t randomizer[BT_EAD_RANDOMIZER_SIZE], const uint8_t *payload,
141 			size_t payload_size, uint8_t *encrypted_payload)
142 {
143 	CHECKIF(session_key == NULL) {
144 		LOG_DBG("session_key is NULL");
145 		return -EINVAL;
146 	}
147 
148 	CHECKIF(iv == NULL) {
149 		LOG_DBG("iv is NULL");
150 		return -EINVAL;
151 	}
152 
153 	CHECKIF(randomizer == NULL) {
154 		LOG_DBG("randomizer is NULL");
155 		return -EINVAL;
156 	}
157 
158 	CHECKIF(payload == NULL) {
159 		LOG_DBG("payload is NULL");
160 		return -EINVAL;
161 	}
162 
163 	CHECKIF(encrypted_payload == NULL) {
164 		LOG_DBG("encrypted_payload is NULL");
165 		return -EINVAL;
166 	}
167 
168 	if (payload_size == 0) {
169 		LOG_WRN("payload_size is set to 0. The encrypted result will be filled with only "
170 			"the Randomizer and the MIC.");
171 	}
172 
173 	return ead_encrypt(session_key, iv, randomizer, payload, payload_size, encrypted_payload);
174 }
175 
176 #endif /* CONFIG_BT_TESTING */
177 
ead_decrypt(const uint8_t session_key[BT_EAD_KEY_SIZE],const uint8_t iv[BT_EAD_IV_SIZE],const uint8_t * encrypted_payload,size_t encrypted_payload_size,uint8_t * payload)178 static int ead_decrypt(const uint8_t session_key[BT_EAD_KEY_SIZE], const uint8_t iv[BT_EAD_IV_SIZE],
179 		       const uint8_t *encrypted_payload, size_t encrypted_payload_size,
180 		       uint8_t *payload)
181 {
182 	int err;
183 	uint8_t nonce[BT_EAD_NONCE_SIZE];
184 	const uint8_t *encrypted_ad_data = &encrypted_payload[BT_EAD_RANDOMIZER_SIZE];
185 	size_t encrypted_ad_data_size = encrypted_payload_size - BT_EAD_RANDOMIZER_SIZE;
186 	size_t payload_size = encrypted_ad_data_size - BT_EAD_MIC_SIZE;
187 
188 	const uint8_t *randomizer = encrypted_payload;
189 
190 	err = bt_ead_generate_nonce(iv, randomizer, nonce);
191 	if (err != 0) {
192 		return -EIO;
193 	}
194 
195 	LOG_HEXDUMP_DBG(encrypted_ad_data, encrypted_ad_data_size, "Encrypted Data: ");
196 
197 	err = bt_ccm_decrypt(session_key, nonce, encrypted_ad_data, payload_size, bt_ead_aad,
198 			     BT_EAD_AAD_SIZE, payload, BT_EAD_MIC_SIZE);
199 	LOG_HEXDUMP_DBG(payload, payload_size, "Decrypted Data: ");
200 	if (err != 0) {
201 		LOG_DBG("Failed to decrypt the data (bt_ccm_decrypt err %d)", err);
202 		return -EIO;
203 	}
204 
205 	return 0;
206 }
207 
bt_ead_decrypt(const uint8_t session_key[BT_EAD_KEY_SIZE],const uint8_t iv[BT_EAD_IV_SIZE],const uint8_t * encrypted_payload,size_t encrypted_payload_size,uint8_t * payload)208 int bt_ead_decrypt(const uint8_t session_key[BT_EAD_KEY_SIZE], const uint8_t iv[BT_EAD_IV_SIZE],
209 		   const uint8_t *encrypted_payload, size_t encrypted_payload_size,
210 		   uint8_t *payload)
211 {
212 	CHECKIF(session_key == NULL) {
213 		LOG_DBG("session_key is NULL");
214 		return -EINVAL;
215 	}
216 
217 	CHECKIF(iv == NULL) {
218 		LOG_DBG("iv is NULL");
219 		return -EINVAL;
220 	}
221 
222 	CHECKIF(encrypted_payload == NULL) {
223 		LOG_DBG("encrypted_payload is NULL");
224 		return -EINVAL;
225 	}
226 
227 	CHECKIF(payload == NULL) {
228 		LOG_DBG("payload is NULL");
229 		return -EINVAL;
230 	}
231 
232 	if (encrypted_payload_size < BT_EAD_RANDOMIZER_SIZE + BT_EAD_MIC_SIZE) {
233 		LOG_DBG("encrypted_payload_size is not large enough.");
234 		return -EINVAL;
235 	} else if (encrypted_payload_size == BT_EAD_RANDOMIZER_SIZE + BT_EAD_MIC_SIZE) {
236 		LOG_WRN("encrypted_payload_size not large enough to contain encrypted data.");
237 	}
238 
239 	return ead_decrypt(session_key, iv, encrypted_payload, encrypted_payload_size, payload);
240 }
241