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