xref: /freebsd/contrib/wpa/src/nan/nan_crypto.c (revision 71e72c9e91c4b8007a4292e09669e8b549c29e97)
1 /*
2  * Wi-Fi Aware - NAN Data link cryptography functions
3  * Copyright (C) 2025 Intel Corporation
4  *
5  * This software may be distributed under the terms of the BSD license.
6  * See README for more details.
7  */
8 
9 #include "includes.h"
10 #include "utils/common.h"
11 #include "common/ieee802_11_common.h"
12 #include "crypto/sha256.h"
13 #include "crypto/sha384.h"
14 #include "crypto/crypto.h"
15 #include "crypto/aes_wrap.h"
16 #include "nan_i.h"
17 
18 #define NAN_KCK_MAX_LEN 24
19 #define NAN_KEK_MAX_LEN 32
20 #define NAN_TK_MAX_LEN  32
21 
22 #define NAN_PTK_LABEL       "NAN Pairwise key expansion"
23 #define NAN_PMKID_LABEL     "NAN PMK Name"
24 
25 /* NAN ciphers use only SHA-256 and SHA-384, and SHA-384 has a bigger digest */
26 #define MAX_MAC_LEN SHA384_MAC_LEN
27 
28 
nan_crypto_cipher_kck_len(enum nan_cipher_suite_id cipher)29 static size_t nan_crypto_cipher_kck_len(enum nan_cipher_suite_id cipher)
30 {
31 	switch (cipher) {
32 	case NAN_CS_SK_CCM_128:
33 	case NAN_CS_PK_PASN_128:
34 		return 16;
35 	case NAN_CS_SK_GCM_256:
36 	case NAN_CS_PK_PASN_256:
37 		return 24;
38 	default:
39 		return 0;
40 	}
41 }
42 
43 
nan_crypto_cipher_kek_len(enum nan_cipher_suite_id cipher)44 static size_t nan_crypto_cipher_kek_len(enum nan_cipher_suite_id cipher)
45 {
46 	switch (cipher) {
47 	case NAN_CS_SK_CCM_128:
48 	case NAN_CS_PK_PASN_128:
49 		return 16;
50 	case NAN_CS_SK_GCM_256:
51 	case NAN_CS_PK_PASN_256:
52 		return 32;
53 	default:
54 		return 0;
55 	}
56 }
57 
58 
nan_cipher_key_len(enum nan_cipher_suite_id cipher)59 static size_t nan_cipher_key_len(enum nan_cipher_suite_id cipher)
60 {
61 	switch (cipher) {
62 	case NAN_CS_SK_CCM_128:
63 	case NAN_CS_PK_PASN_128:
64 		return 16;
65 	case NAN_CS_SK_GCM_256:
66 	case NAN_CS_PK_PASN_256:
67 		return 32;
68 	default:
69 		return 0;
70 	}
71 }
72 
73 
nan_crypto_sha256(const u8 * plaintext,size_t psize,u8 * output)74 static int nan_crypto_sha256(const u8 *plaintext, size_t psize, u8 *output)
75 {
76 	const u8 *addrs[1];
77 	size_t lens[1];
78 
79 	addrs[0] = plaintext;
80 	lens[0] = psize;
81 
82 	return sha256_vector(1, addrs, lens, output);
83 }
84 
85 
nan_crypto_sha384(const u8 * plaintext,size_t psize,u8 * output)86 static int nan_crypto_sha384(const u8 *plaintext, size_t psize, u8 *output)
87 {
88 	const u8 *addrs[1];
89 	size_t lens[1];
90 
91 	addrs[0] = plaintext;
92 	lens[0] = psize;
93 
94 	return sha384_vector(1, addrs,  lens, output);
95 }
96 
97 
98 /**
99  * nan_crypto_pmk_to_ptk - Calculate PTK from PMK, addresses, and nonces
100  * @pmk: Pairwise master key
101  * @iaddr: Initiator address
102  * @raddr: Remote address
103  * @inonce: Initiator nonce
104  * @rnonce: Remote nonce
105  * @ptk: Buffer for Pairwise Transient Key
106  * @cipher: Negotiated pairwise cipher
107  * returns: 0 on success, negative value of failure
108  */
nan_crypto_pmk_to_ptk(const u8 * pmk,const u8 * iaddr,const u8 * raddr,const u8 * inonce,const u8 * rnonce,struct nan_ptk * ptk,enum nan_cipher_suite_id cipher)109 int nan_crypto_pmk_to_ptk(const u8 *pmk, const u8 *iaddr, const u8 *raddr,
110 			  const u8 *inonce, const u8 *rnonce,
111 			  struct nan_ptk *ptk,
112 			  enum nan_cipher_suite_id cipher)
113 {
114 	u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN];
115 	u8 tmp[NAN_KCK_MAX_LEN + NAN_KEK_MAX_LEN + NAN_TK_MAX_LEN];
116 	size_t ptk_len;
117 	int ret;
118 
119 	if (!NAN_CS_IS_VALID_NDP(cipher))
120 		return -1;
121 
122 	if (!ptk)
123 		return -1;
124 
125 	os_memcpy(data, iaddr, ETH_ALEN);
126 	os_memcpy(data + ETH_ALEN, raddr, ETH_ALEN);
127 	os_memcpy(data + 2 * ETH_ALEN, inonce, WPA_NONCE_LEN);
128 	os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, rnonce,
129 		  WPA_NONCE_LEN);
130 
131 	ptk->kck_len = nan_crypto_cipher_kck_len(cipher);
132 	ptk->kek_len = nan_crypto_cipher_kek_len(cipher);
133 	ptk->tk_len = nan_cipher_key_len(cipher);
134 	ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len;
135 
136 	if (NAN_CS_IS_128(cipher))
137 		ret = sha256_prf(pmk, PMK_LEN, NAN_PTK_LABEL, data,
138 				 sizeof(data), tmp, ptk_len);
139 	else
140 		ret = sha384_prf(pmk, PMK_LEN, NAN_PTK_LABEL, data,
141 				 sizeof(data), tmp, ptk_len);
142 	if (ret)
143 		goto out;
144 
145 	wpa_hexdump_key(MSG_DEBUG, "NAN: PMK", pmk, PMK_LEN);
146 	wpa_hexdump_key(MSG_DEBUG, "NAN: iaddr", iaddr, ETH_ALEN);
147 	wpa_hexdump_key(MSG_DEBUG, "NAN: raddr", raddr, ETH_ALEN);
148 	wpa_hexdump_key(MSG_DEBUG, "NAN: inonce", inonce, WPA_NONCE_LEN);
149 	wpa_hexdump_key(MSG_DEBUG, "NAN: rnonce", rnonce, WPA_NONCE_LEN);
150 	wpa_hexdump_key(MSG_DEBUG, "NAN: PTK", tmp, ptk_len);
151 
152 	os_memcpy(ptk->kck, tmp, ptk->kck_len);
153 	wpa_hexdump_key(MSG_DEBUG, "NAN: KCK", ptk->kck, ptk->kck_len);
154 
155 	os_memcpy(ptk->kek, tmp + ptk->kck_len, ptk->kek_len);
156 	wpa_hexdump_key(MSG_DEBUG, "NAN: KEK", ptk->kek, ptk->kek_len);
157 
158 	os_memcpy(ptk->tk, tmp + ptk->kck_len + ptk->kek_len, ptk->tk_len);
159 	wpa_hexdump_key(MSG_DEBUG, "NAN: TK", ptk->tk, ptk->tk_len);
160 
161 out:
162 	forced_memzero(data, sizeof(data));
163 	forced_memzero(tmp, sizeof(tmp));
164 	return ret;
165 }
166 
167 
168 /*
169  * nan_crypto_calc_pmkid - Calculate a NAN PMKID
170  * @pmk: Pairwise Master Key
171  * @iaddr: Initiator address
172  * @raddr: Remote address
173  * @serv_id: ID of the service providing the PMK
174  * @cipher: Negotiated pairwise cipher
175  * @pmkid: Buffer to hold the pmkid
176  * Returns: 0 on success, negative value of failure
177  */
nan_crypto_calc_pmkid(const u8 * pmk,const u8 * iaddr,const u8 * raddr,const u8 * serv_id,enum nan_cipher_suite_id cipher,u8 * pmkid)178 int nan_crypto_calc_pmkid(const u8 *pmk, const u8 *iaddr, const u8 *raddr,
179 			  const u8 *serv_id,
180 			  enum nan_cipher_suite_id cipher, u8 *pmkid)
181 {
182 	u8 data[sizeof(NAN_PMKID_LABEL) - 1 + 2 * ETH_ALEN +
183 		NAN_SERVICE_ID_LEN];
184 	u8 digest[MAX_MAC_LEN];
185 	int ret;
186 
187 	os_memset(data, 0, sizeof(data));
188 	os_memset(digest, 0, sizeof(digest));
189 
190 	if (!NAN_CS_IS_VALID_NDP(cipher))
191 		return -1;
192 
193 	if (!serv_id || is_zero_ether_addr(serv_id))
194 		return -1;
195 
196 	os_memcpy(data, NAN_PMKID_LABEL, sizeof(NAN_PMKID_LABEL) - 1);
197 	os_memcpy(data + sizeof(NAN_PMKID_LABEL) - 1, iaddr, ETH_ALEN);
198 	os_memcpy(data + sizeof(NAN_PMKID_LABEL) - 1 + ETH_ALEN, raddr,
199 		  ETH_ALEN);
200 	os_memcpy(data + sizeof(NAN_PMKID_LABEL) - 1 + 2 * ETH_ALEN, serv_id,
201 		  NAN_SERVICE_ID_LEN);
202 
203 	wpa_hexdump_key(MSG_DEBUG, "NAN: PMKID data", data, sizeof(data));
204 
205 	if (NAN_CS_IS_128(cipher))
206 		ret = hmac_sha256(pmk, PMK_LEN, data, sizeof(data), digest);
207 	else
208 		ret = hmac_sha384(pmk, PMK_LEN, data, sizeof(data), digest);
209 	if (ret)
210 		goto out;
211 
212 	os_memcpy(pmkid, digest, PMKID_LEN);
213 	wpa_hexdump_key(MSG_DEBUG, "NAN: PMKID", pmkid, PMKID_LEN);
214 
215 out:
216 	forced_memzero(digest, sizeof(digest));
217 	return ret;
218 }
219 
220 
221 /**
222  * nan_crypto_calc_auth_token - Calculate authentication token
223  * @buf: Buffer on which to calculate the authentication token
224  * @len: Length of &buf in octets
225  * @cipher: Negotiated NAN cipher
226  * @token: Buffer to hold the token (NAN_AUTH_TOKEN_LEN octets)
227  * Returns: 0 on success, and a negative error value on failure.
228  */
nan_crypto_calc_auth_token(enum nan_cipher_suite_id cipher,const u8 * buf,size_t len,u8 * token)229 int nan_crypto_calc_auth_token(enum nan_cipher_suite_id cipher,
230 			       const u8 *buf, size_t len, u8 *token)
231 {
232 	u8 hash[MAX_MAC_LEN];
233 	int ret;
234 
235 	if (!NAN_CS_IS_VALID_NDP(cipher))
236 		return -1;
237 
238 	if (NAN_CS_IS_128(cipher))
239 		ret = nan_crypto_sha256(buf, len, hash);
240 	else
241 		ret = nan_crypto_sha384(buf, len, hash);
242 	if (ret)
243 		return ret;
244 
245 	os_memcpy(token, hash, NAN_AUTH_TOKEN_LEN);
246 	wpa_hexdump_key(MSG_DEBUG, "NAN: AUTH_TOKEN_DATA", buf, len);
247 	wpa_hexdump_key(MSG_DEBUG, "NAN: AUTH TOKEN", token,
248 			NAN_AUTH_TOKEN_LEN);
249 
250 	forced_memzero(hash, sizeof(hash));
251 
252 	return ret;
253 }
254 
255 
256 /*
257  * nan_crypto_key_mic - Calculate MIC over the given buffer
258  * @buf: Buffer on which to calculate the MIC
259  * @len: Length of &buf
260  * @kck: Key Confirmation Key
261  * @kck_len: Length of &kck
262  * @cipher: Cipher suite identifier.
263  * @mic: On successful return, would hold the MIC.
264  * Return: 0 on success, and a negative error value on failure.
265  */
nan_crypto_key_mic(const u8 * buf,size_t len,const u8 * kck,size_t kck_len,u8 cipher,u8 * mic)266 int nan_crypto_key_mic(const u8 *buf, size_t len, const u8 *kck,
267 		       size_t kck_len, u8 cipher, u8 *mic)
268 {
269 	u8 digest[MAX_MAC_LEN];
270 	u8 mic_len;
271 	int ret;
272 
273 	os_memset(digest, 0, sizeof(digest));
274 
275 	if (!NAN_CS_IS_VALID_NDP(cipher))
276 		return -1;
277 
278 	wpa_hexdump_key(MSG_DEBUG, "NAN: MIC data", buf, len);
279 	wpa_hexdump_key(MSG_DEBUG, "NAN: KCK", kck, kck_len);
280 
281 	if (NAN_CS_IS_128(cipher)) {
282 		mic_len = NAN_KEY_MIC_LEN;
283 		ret = hmac_sha256(kck, kck_len, buf, len, digest);
284 	} else {
285 		mic_len = NAN_KEY_MIC_24_LEN;
286 		ret = hmac_sha384(kck, kck_len, buf, len, digest);
287 	}
288 	if (ret)
289 		return ret;
290 
291 	os_memcpy(mic, digest, mic_len);
292 	forced_memzero(digest, sizeof(digest));
293 
294 	wpa_hexdump_key(MSG_DEBUG, "NAN: MIC", mic, mic_len);
295 	return 0;
296 }
297 
298 
nan_crypto_derive_nd_pmk(const char * pwd,const u8 * service_id,enum nan_cipher_suite_id csid,const u8 * peer_nmi,u8 * nd_pmk)299 int nan_crypto_derive_nd_pmk(const char *pwd, const u8 *service_id,
300 			     enum nan_cipher_suite_id csid,
301 			     const u8 *peer_nmi, u8 *nd_pmk)
302 {
303 	u8 salt[1 + 1 + NAN_SERVICE_ID_LEN + ETH_ALEN];
304 
305 	salt[0] = 0;
306 	salt[1] = (u8) csid;
307 	os_memcpy(salt + 2, service_id, NAN_SERVICE_ID_LEN);
308 	os_memcpy(salt + 2 + NAN_SERVICE_ID_LEN, peer_nmi, ETH_ALEN);
309 
310 	switch (csid) {
311 	case NAN_CS_SK_CCM_128:
312 	case NAN_CS_PK_PASN_128:
313 		return pbkdf2_sha256(pwd, salt, sizeof(salt), 4096, nd_pmk, 32);
314 	case NAN_CS_SK_GCM_256:
315 	case NAN_CS_PK_PASN_256:
316 		return pbkdf2_sha384(pwd, salt, sizeof(salt), 4096, nd_pmk, 32);
317 	default:
318 		return -1;
319 	}
320 }
321 
322 
323 /**
324  * nan_crypto_derive_nira_tag - Derive NIRA tag
325  * @nik: NAN Identity Key
326  * @nik_len: Length of &nik in bytes
327  * @nmi_addr: NAN Management Interface address (6 bytes)
328  * @nira_nonce: NIRA nonce (8 bytes)
329  * Returns: wpabuf containing the derived tag (8 bytes) or %NULL on failure
330  *
331  * Derives a NIRA tag for cipher version 0 using HMAC-SHA-256:
332  * Tag = Truncate-64(HMAC-SHA-256(NIK, "NIR" || NMI Address || Nonce))
333  * The caller is responsible for freeing the returned wpabuf using
334  * wpabuf_free().
335  */
nan_crypto_derive_nira_tag(const u8 * nik,size_t nik_len,const u8 * nmi_addr,const u8 * nira_nonce)336 struct wpabuf * nan_crypto_derive_nira_tag(const u8 *nik, size_t nik_len,
337 					   const u8 *nmi_addr,
338 					   const u8 *nira_nonce)
339 {
340 	u8 data[NAN_NIRA_STR_LEN + ETH_ALEN + NAN_NIRA_NONCE_LEN];
341 	u8 tag[SHA256_MAC_LEN];
342 	struct wpabuf *tag_buf;
343 
344 	if (!nik || nik_len != NAN_NIK_LEN) {
345 		wpa_printf(MSG_INFO,
346 			   "NAN: Invalid NIK for tag derivation (len=%zu)",
347 			   nik ? nik_len : 0);
348 		return NULL;
349 	}
350 
351 	if (!nmi_addr || !nira_nonce) {
352 		wpa_printf(MSG_INFO,
353 			   "NAN: Invalid parameters for tag derivation");
354 		return NULL;
355 	}
356 
357 	/* Tag = Truncate-64(HMAC-SHA-256(NIK, “NIR”, NMI || Nonce)) */
358 
359 	/* Construct data: "NIR" || NMI Address || Nonce */
360 	os_memcpy(data, NAN_NIRA_STR, NAN_NIRA_STR_LEN);
361 	os_memcpy(&data[NAN_NIRA_STR_LEN], nmi_addr, ETH_ALEN);
362 	os_memcpy(&data[NAN_NIRA_STR_LEN + ETH_ALEN], nira_nonce,
363 		  NAN_NIRA_NONCE_LEN);
364 
365 	/* Compute HMAC-SHA-256(NIK, data) */
366 	if (hmac_sha256(nik, NAN_NIK_LEN, data, sizeof(data), tag) < 0) {
367 		wpa_printf(MSG_INFO, "NAN: Failed to compute HMAC for tag");
368 		return NULL;
369 	}
370 
371 	tag_buf = wpabuf_alloc_copy(tag, NAN_NIRA_TAG_LEN);
372 	if (!tag_buf)
373 		wpa_printf(MSG_INFO, "NAN: Failed to allocate tag buffer");
374 	else
375 		wpa_hexdump(MSG_DEBUG, "NAN: Derived NIRA tag",
376 			    wpabuf_head(tag_buf), wpabuf_len(tag_buf));
377 
378 	forced_memzero(tag, sizeof(tag));
379 	return tag_buf;
380 }
381 
382 
383 /**
384  * nan_crypto_derive_from_kdk - Derive a key from KDK using KDF-HASH-NNN
385  * @kdk: Key Derivation Key
386  * @kdk_len: Length of KDK in bytes
387  * @cipher: Cipher suite identifier (NAN_CS_PK_PASN_128 or NAN_CS_PK_PASN_256)
388  * @label: Label string for the key derivation
389  * @initiator_nmi: Pairing Initiator NMI address (6 bytes)
390  * @responder_nmi: Pairing Responder NMI address (6 bytes)
391  * @key: Buffer for the derived key
392  * @key_len: number of bytes to derive
393  * Returns: 0 on success, -1 on failure
394  *
395  * Generic function to derive a key from KDK using:
396  * KEY = KDF-HASH-NNN(KDK, label, Initiator NMI || Responder NMI)
397  */
nan_crypto_derive_from_kdk(const u8 * kdk,size_t kdk_len,enum nan_cipher_suite_id cipher,const char * label,const u8 * initiator_nmi,const u8 * responder_nmi,u8 * key,size_t key_len)398 static int nan_crypto_derive_from_kdk(const u8 *kdk, size_t kdk_len,
399 				      enum nan_cipher_suite_id cipher,
400 				      const char *label,
401 				      const u8 *initiator_nmi,
402 				      const u8 *responder_nmi,
403 				      u8 *key, size_t key_len)
404 {
405 	u8 data[ETH_ALEN * 2];
406 	int ret = 0;
407 
408 	if (!kdk || !kdk_len || !label || !initiator_nmi || !responder_nmi ||
409 	    !key || !key_len) {
410 		wpa_printf(MSG_INFO,
411 			   "NAN: Invalid parameters for NPK/KEK derivation");
412 		return -1;
413 	}
414 
415 	/* Concatenate: Pairing Initiator NMI || Pairing Responder NMI */
416 	os_memcpy(data, initiator_nmi, ETH_ALEN);
417 	os_memcpy(data + ETH_ALEN, responder_nmi, ETH_ALEN);
418 
419 	if (cipher == NAN_CS_PK_PASN_128) {
420 		ret = sha256_prf(kdk, kdk_len, label, data, sizeof(data), key,
421 				 key_len);
422 	} else if (cipher == NAN_CS_PK_PASN_256) {
423 		ret = sha384_prf(kdk, kdk_len, label, data, sizeof(data), key,
424 				 key_len);
425 	} else {
426 		wpa_printf(MSG_INFO,
427 			   "NAN: Unsupported cipher suite for key derivation: %d",
428 			   cipher);
429 		return -1;
430 	}
431 
432 	if (ret) {
433 		wpa_printf(MSG_INFO,
434 			   "NAN: NPK/KEK derivation failed (ret=%d)", ret);
435 		return ret;
436 	}
437 
438 	wpa_hexdump_key(MSG_DEBUG, "NAN: KDK", kdk, kdk_len);
439 	wpa_printf(MSG_DEBUG, "NAN: Label: %s", label);
440 	wpa_printf(MSG_DEBUG, "NAN: Initiator NMI " MACSTR,
441 		   MAC2STR(initiator_nmi));
442 	wpa_printf(MSG_DEBUG, "NAN: Responder NMI " MACSTR,
443 		   MAC2STR(responder_nmi));
444 	wpa_hexdump_key(MSG_DEBUG, "NAN: Derived key", key, key_len);
445 
446 	return 0;
447 }
448 
449 
450 /**
451  * nan_crypto_derive_npk - Derive NPK from NM-KDK for opportunistic pairing
452  * @kdk: NM-KDK (NAN Master Key Derivation Key)
453  * @kdk_len: Length of KDK in bytes
454  * @cipher: Cipher suite identifier (NAN_CS_PK_PASN_128 or NAN_CS_PK_PASN_256)
455  * @initiator_nmi: Pairing Initiator NMI address (6 bytes)
456  * @responder_nmi: Pairing Responder NMI address (6 bytes)
457  * @buf: Buffer for the derived NPK
458  * @buf_len: Length of the buffer  (must be 32 bytes)
459  * Returns: 0 on success, -1 on failure
460  *
461  * NPK = KDF-HASH-256(NM-KDK, "NAN Opportunistic NPK Derivation",
462  *                    Pairing Initiator NMI || Pairing Responder NMI)
463  *
464  * Note: It is unclear whether KDF-HASH-256 means that SHA-256 must be used as
465  * the hash algorithm, or the hash algorithm is determined by the cipher suite.
466  * Usually, NCS-PK-PASN-128 cipher comes with SHA-256 and NCS-PK-PASN-256 with
467  * SHA-384 as defined in Wi-Fi Aware Specification v4.0, section 7.1.2. But for
468  * opportunistic pairing, section 7.6.4.3 specifies KDF-HASH-256 only for NPK
469  * derivation. Does this mean that SHA-256 must be used? In IEEE 802.11-2024,
470  * 12.13.8, where KDF-HASH-NNN is defined, NNN is the number of bits to derive,
471  * not the hash function. Therefore, we follow the latter interpretation and use
472  * the hash function corresponding to the cipher suite.
473  */
nan_crypto_derive_npk(const u8 * kdk,size_t kdk_len,enum nan_cipher_suite_id cipher,const u8 * initiator_nmi,const u8 * responder_nmi,u8 * buf,size_t buf_len)474 int nan_crypto_derive_npk(const u8 *kdk, size_t kdk_len,
475 			  enum nan_cipher_suite_id cipher,
476 			  const u8 *initiator_nmi, const u8 *responder_nmi,
477 			  u8 *buf, size_t buf_len)
478 {
479 	const char *label = "NAN Opportunistic NPK Derivation";
480 
481 	wpa_printf(MSG_DEBUG, "NAN: Deriving NPK from NM-KDK");
482 
483 	if (buf_len < NAN_NPK_LEN) {
484 		wpa_printf(MSG_INFO, "NAN: NPK buffer too small: %zu bytes",
485 			   buf_len);
486 		return -1;
487 	}
488 
489 	return nan_crypto_derive_from_kdk(kdk, kdk_len, cipher, label,
490 					  initiator_nmi, responder_nmi,
491 					  buf, buf_len);
492 }
493 
494 
495 /**
496  * nan_crypto_derive_kek - Derive KEK from NM-KDK
497  * @kdk: NM-KDK (NAN Master Key Derivation Key)
498  * @kdk_len: Length of KDK in bytes
499  * @cipher: Cipher suite identifier (NAN_CS_PK_PASN_128 or NAN_CS_PK_PASN_256)
500  * @initiator_nmi: Pairing Initiator NMI address (6 bytes)
501  * @responder_nmi: Pairing Responder NMI address (6 bytes)
502  * @ptk: Buffer for the derived KEK
503  * Returns: 0 on success, -1 on failure
504  *
505  * NM-KEK = KDF-HASH-MMM(NM-KDK, "NAN Management KEK Derivation",
506  *                       Pairing Initiator NMI || Pairing Responder NMI)
507  */
nan_crypto_derive_kek(const u8 * kdk,size_t kdk_len,enum nan_cipher_suite_id cipher,const u8 * initiator_nmi,const u8 * responder_nmi,struct wpa_ptk * ptk)508 int nan_crypto_derive_kek(const u8 *kdk, size_t kdk_len,
509 			  enum nan_cipher_suite_id cipher,
510 			  const u8 *initiator_nmi, const u8 *responder_nmi,
511 			  struct wpa_ptk *ptk)
512 {
513 	const char *label = "NAN Management KEK Derivation";
514 
515 	wpa_printf(MSG_DEBUG, "NAN: Deriving KEK from NM-KDK");
516 
517 	if (cipher != NAN_CS_PK_PASN_128 &&
518 	    cipher != NAN_CS_PK_PASN_256) {
519 		wpa_printf(MSG_INFO,
520 			   "NAN: Unsupported cipher suite for KEK derivation: %d",
521 			   cipher);
522 		return -1;
523 	}
524 
525 	ptk->kek_len = nan_crypto_cipher_kek_len(cipher);
526 
527 	return nan_crypto_derive_from_kdk(kdk, kdk_len, cipher, label,
528 					  initiator_nmi, responder_nmi,
529 					  ptk->kek, ptk->kek_len);
530 }
531 
532 
533 /**
534  * nan_crypto_derive_nd_pmk_from_kdk - Derive ND-PMK from NM-KDK
535  * @kdk: NM-KDK (NAN Master Key Derivation Key)
536  * @kdk_len: Length of KDK in bytes
537  * @cipher: Cipher suite identifier (NAN_CS_PK_PASN_128 or NAN_CS_PK_PASN_256)
538  * @initiator_nmi: Pairing Initiator NMI address (6 bytes)
539  * @responder_nmi: Pairing Responder NMI address (6 bytes)
540  * @nd_pmk: Buffer for the derived ND-PMK (must be 32 bytes)
541  * Returns: 0 on success, -1 on failure
542  *
543  * ND-PMK = KDF-HASH-256(NM-KDK, "NDP PMK Derivation",
544  *                       Pairing Initiator NMI || Pairing Responder NMI)
545  */
nan_crypto_derive_nd_pmk_from_kdk(const u8 * kdk,size_t kdk_len,enum nan_cipher_suite_id cipher,const u8 * initiator_nmi,const u8 * responder_nmi,u8 * nd_pmk)546 int nan_crypto_derive_nd_pmk_from_kdk(const u8 *kdk, size_t kdk_len,
547 				      enum nan_cipher_suite_id cipher,
548 				      const u8 *initiator_nmi,
549 				      const u8 *responder_nmi, u8 *nd_pmk)
550 {
551 	const char *label = "NDP PMK Derivation";
552 
553 	wpa_printf(MSG_DEBUG, "NAN: Deriving ND-PMK from NM-KDK");
554 
555 	/* ND-PMK always uses SHA-256, resulting in 32 bytes */
556 	return nan_crypto_derive_from_kdk(kdk, kdk_len, cipher, label,
557 					  initiator_nmi, responder_nmi, nd_pmk,
558 					  PMK_LEN);
559 }
560 
561 
562 /**
563  * nan_crypto_encrypt_key - Encrypt key data using AES Key Wrap (RFC 3394)
564  * @key_data: Key data to be encrypted
565  * @kek: Key Encryption Key (KEK)
566  * @kek_len: Length of KEK in octets
567  * Returns: Encrypted key data in a newly allocated wpabuf, or NULL on failure.
568  *
569  * This function encrypts the provided key data using AES Key Wrap algorithm
570  * as defined in RFC 3394. The input data is padded to 8-byte alignment before
571  * encryption. The padding scheme uses 0xdd as the first padding byte followed
572  * by zeros.
573  *
574  * The caller is responsible for freeing the returned wpabuf.
575  */
nan_crypto_encrypt_key_data(const struct wpabuf * key_data,const u8 * kek,size_t kek_len)576 struct wpabuf * nan_crypto_encrypt_key_data(const struct wpabuf *key_data,
577 					    const u8 *kek, size_t kek_len)
578 {
579 	size_t key_data_len;
580 	size_t pad;
581 	size_t padded_len;
582 	u8 *padded_key_data;
583 	struct wpabuf *encrypted_key_data;
584 
585 	if (!key_data || !kek || !kek_len) {
586 		wpa_printf(MSG_INFO,
587 			   "NAN: Pairing: Invalid parameters for key data encryption");
588 		return NULL;
589 	}
590 
591 	key_data_len = wpabuf_len(key_data);
592 	if (!key_data_len) {
593 		wpa_printf(MSG_INFO,
594 			   "NAN: Pairing: Key data is empty for encryption");
595 		return NULL;
596 	}
597 
598 	wpa_hexdump_key(MSG_DEBUG, "NAN: Plain key data", wpabuf_head(key_data),
599 			key_data_len);
600 
601 	/* Calculate padding to align to 8 bytes (AES block size) */
602 	pad = key_data_len % 8;
603 	if (pad)
604 		pad = 8 - pad;
605 
606 	padded_len = key_data_len + pad;
607 	padded_key_data = os_zalloc(padded_len);
608 	if (!padded_key_data)
609 		return NULL;
610 
611 	/* Copy key data and apply padding (0xdd followed by zeros) */
612 	os_memcpy(padded_key_data, wpabuf_head(key_data), key_data_len);
613 	if (pad)
614 		padded_key_data[key_data_len] = 0xdd;
615 
616 	/* Allocate buffer for encrypted data (input length + 8 bytes for IV) */
617 	encrypted_key_data = wpabuf_alloc(padded_len + 8);
618 	if (!encrypted_key_data)
619 		goto fail;
620 
621 	/* Encrypt the padded data using AES Key Wrap */
622 	if (aes_wrap(kek, kek_len, padded_len / 8, padded_key_data,
623 		     wpabuf_put(encrypted_key_data, padded_len + 8))) {
624 		wpa_printf(MSG_INFO, "NAN: Pairing: AES wrap failed");
625 		wpabuf_free(encrypted_key_data);
626 		encrypted_key_data = NULL;
627 	} else {
628 		wpa_hexdump(MSG_DEBUG, "NAN: Encrypted key data",
629 			    wpabuf_head(encrypted_key_data),
630 			    wpabuf_len(encrypted_key_data));
631 	}
632 
633 fail:
634 	bin_clear_free(padded_key_data, padded_len);
635 	return encrypted_key_data;
636 }
637 
638 
639 /**
640  * nan_crypto_decrypt_key_data - Decrypt NAN key data using AES-UNWRAP
641  * @kek: Key Encryption Key
642  * @kek_len: KEK length in bytes
643  * @encrypted_data: Encrypted key data to decrypt
644  * @encrypted_len: Length of encrypted data in bytes
645  * Returns: wpabuf containing decrypted data or %NULL on failure
646  *
647  * This function decrypts NAN key data that was encrypted using AES-WRAP.
648  * The encrypted data must be at least 16 bytes and a multiple of 8 bytes
649  * (AES-WRAP requirement). The caller is responsible for freeing the returned
650  * wpabuf using wpabuf_free().
651  */
nan_crypto_decrypt_key_data(const u8 * kek,size_t kek_len,const u8 * encrypted_data,size_t encrypted_len)652 struct wpabuf * nan_crypto_decrypt_key_data(const u8 *kek, size_t kek_len,
653 					    const u8 *encrypted_data,
654 					    size_t encrypted_len)
655 {
656 	struct wpabuf *decrypted;
657 	size_t plain_len;
658 	u8 *buf;
659 
660 	if (!encrypted_data || !encrypted_len) {
661 		wpa_printf(MSG_INFO, "NAN: Invalid encrypted key data");
662 		return NULL;
663 	}
664 
665 	wpa_hexdump_key(MSG_DEBUG, "NAN: Encrypted key data",
666 			encrypted_data, encrypted_len);
667 
668 	if (!kek || !kek_len) {
669 		wpa_printf(MSG_INFO,
670 			   "NAN: No KEK available for key data decryption");
671 		return NULL;
672 	}
673 
674 	wpa_hexdump_key(MSG_DEBUG, "NAN: KEK for decryption", kek, kek_len);
675 
676 	/* AES-WRAP adds 8 bytes overhead */
677 	if (encrypted_len < 16 || encrypted_len % 8 != 0) {
678 		wpa_printf(MSG_INFO,
679 			   "NAN: Invalid encrypted key data length %zu",
680 			   encrypted_len);
681 		return NULL;
682 	}
683 
684 	plain_len = encrypted_len - 8;
685 	decrypted = wpabuf_alloc(plain_len);
686 	if (!decrypted) {
687 		wpa_printf(MSG_INFO,
688 			   "NAN: Failed to allocate decryption buffer");
689 		return NULL;
690 	}
691 
692 	buf = wpabuf_put(decrypted, plain_len);
693 	if (aes_unwrap(kek, kek_len, plain_len / 8, encrypted_data, buf)) {
694 		wpa_printf(MSG_INFO,
695 			   "NAN: AES unwrap failed - could not decrypt key data");
696 		wpabuf_free(decrypted);
697 		return NULL;
698 	}
699 
700 	wpa_hexdump_key(MSG_DEBUG, "NAN: Decrypted key data",
701 			wpabuf_head(decrypted), wpabuf_len(decrypted));
702 
703 	return decrypted;
704 }
705 
706 
707 /**
708  * nan_crypto_clear_pmkid_list - Clear and free all entries in a PMKID list
709  * @pmkid_list: List of PMKIDs to clear
710  *
711  * This function removes and frees all PMKID entries from the provided list.
712  */
nan_crypto_clear_pmkid_list(struct dl_list * pmkid_list)713 void nan_crypto_clear_pmkid_list(struct dl_list *pmkid_list)
714 {
715 	struct nan_de_pmkid *p, *n;
716 
717 	dl_list_for_each_safe(p, n, pmkid_list, struct nan_de_pmkid, list) {
718 		dl_list_del(&p->list);
719 		os_free(p);
720 	}
721 }
722 
723 
724 /**
725  * nan_crypto_pmkid_list - Generate PMKIDs for multiple cipher suites
726  * @pmkid_list: List to which the generated PMKIDs are appended
727  * @raddr: Responder MAC address
728  * @srv_id: Service ID (6 bytes)
729  * @cipher_suites: Array of cipher suite identifiers (int_array)
730  * @pmk: PMK for which the PMKIDs are generated
731  * Returns: 0 on success, -1 on failure
732  *
733  * This function generates a PMKID for each cipher suite in the provided array
734  * and adds them to the pmkid_list.
735  */
nan_crypto_pmkid_list(struct dl_list * pmkid_list,const u8 * raddr,const u8 * srv_id,const int * cipher_suites,const u8 * pmk)736 int nan_crypto_pmkid_list(struct dl_list *pmkid_list, const u8 *raddr,
737 			  const u8 *srv_id, const int *cipher_suites,
738 			  const u8 *pmk)
739 {
740 	size_t cs_num = int_array_len(cipher_suites);
741 	size_t i;
742 
743 	if (!cs_num || !pmk)
744 		return 0;
745 
746 	for (i = 0; i < cs_num; i++) {
747 		struct nan_de_pmkid *p;
748 		int ret;
749 		static const u8 iaddr[ETH_ALEN] = {
750 			0xff, 0xff, 0xff, 0xff, 0xff, 0xff
751 		};
752 		enum nan_cipher_suite_id csid =
753 			(enum nan_cipher_suite_id) cipher_suites[i];
754 
755 		p = os_zalloc(sizeof(*p));
756 		if (!p)
757 			return -1;
758 
759 		ret = nan_crypto_calc_pmkid(pmk, iaddr, raddr, srv_id, csid,
760 					    p->pmkid);
761 		if (ret < 0) {
762 			wpa_printf(MSG_DEBUG,
763 				   "NAN: Failed to derive PMKID for cipher suite %d",
764 				   cipher_suites[i]);
765 			nan_crypto_clear_pmkid_list(pmkid_list);
766 			return ret;
767 		}
768 
769 		dl_list_add(pmkid_list, &p->list);
770 	}
771 
772 	return 0;
773 }
774