/** * sha256_prf - SHA256-based Pseudo-Random Function (IEEE 802.11r, 8.5A.3) * @key: Key for PRF * @key_len: Length of the key in bytes * @label: A unique label for each purpose of the PRF * @data: Extra data to bind into the key * @data_len: Length of the data * @buf: Buffer for the generated pseudo-random key * @buf_len: Number of bytes of key to generate * * This function is used to derive new, cryptographically separate keys from a * given key. */ void sha256_prf(const u8 *key, size_t key_len, const char *label, const u8 *data, size_t data_len, u8 *buf, size_t buf_len) { u16 counter = 0; size_t pos, plen; u8 hash[SHA256_MAC_LEN]; const u8 *addr[3]; size_t len[3]; u8 counter_le[2]; addr[0] = counter_le; len[0] = 2; addr[1] = (u8 *) label; len[1] = strlen(label) + 1; addr[2] = data; len[2] = data_len; pos = 0; while (pos < buf_len) { plen = buf_len - pos; WPA_PUT_LE16(counter_le, counter); if (plen >= SHA256_MAC_LEN) { hmac_sha256_vector(key, key_len, 3, addr, len, &buf[pos]); pos += SHA256_MAC_LEN; } else { hmac_sha256_vector(key, key_len, 3, addr, len, hash); memcpy(&buf[pos], hash, plen); break; } counter++; } }
int wps_build_authenticator(struct wps_data *wps, struct wpabuf *msg) { u8 hash[SHA256_MAC_LEN]; const u8 *addr[2]; size_t len[2]; if (wps->last_msg == NULL) { wpa_printf(MSG_DEBUG, "WPS: Last message not available for " "building authenticator"); return -1; } /* Authenticator = HMAC-SHA256_AuthKey(M_prev || M_curr*) * (M_curr* is M_curr without the Authenticator attribute) */ addr[0] = wpabuf_head(wps->last_msg); len[0] = wpabuf_len(wps->last_msg); addr[1] = wpabuf_head(msg); len[1] = wpabuf_len(msg); hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len, hash); wpa_printf(MSG_DEBUG, "WPS: * Authenticator"); wpabuf_put_be16(msg, ATTR_AUTHENTICATOR); wpabuf_put_be16(msg, WPS_AUTHENTICATOR_LEN); wpabuf_put_data(msg, hash, WPS_AUTHENTICATOR_LEN); return 0; }
int wps_process_authenticator(struct wps_data *wps, const u8 *authenticator, const struct wpabuf *msg) { u8 hash[SHA256_MAC_LEN]; const u8 *addr[2]; size_t len[2]; if (authenticator == NULL) { wpa_printf(MSG_DEBUG, "WPS: No Authenticator attribute " "included"); return -1; } if (wps->last_msg == NULL) { wpa_printf(MSG_DEBUG, "WPS: Last message not available for " "validating authenticator"); return -1; } /* Authenticator = HMAC-SHA256_AuthKey(M_prev || M_curr*) * (M_curr* is M_curr without the Authenticator attribute) */ addr[0] = wpabuf_head(wps->last_msg); len[0] = wpabuf_len(wps->last_msg); addr[1] = wpabuf_head(msg); len[1] = wpabuf_len(msg) - 4 - WPS_AUTHENTICATOR_LEN; hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len, hash); if (os_memcmp(hash, authenticator, WPS_AUTHENTICATOR_LEN) != 0) { wpa_printf(MSG_DEBUG, "WPS: Incorrect Authenticator"); return -1; } return 0; }
static int eap_gpsk_gkdf_sha256(const u8 *psk /* Y */, const u8 *data /* Z */, size_t data_len, u8 *buf, size_t len /* X */) { u8 *opos; size_t i, n, hashlen, left, clen; u8 ibuf[2], hash[SHA256_MAC_LEN]; const u8 *addr[2]; size_t vlen[2]; hashlen = SHA256_MAC_LEN; /* M_i = MAC_Y (i || Z); (MAC = HMAC-SHA256) */ addr[0] = ibuf; vlen[0] = sizeof(ibuf); addr[1] = data; vlen[1] = data_len; opos = buf; left = len; n = (len + hashlen - 1) / hashlen; for (i = 1; i <= n; i++) { WPA_PUT_BE16(ibuf, i); hmac_sha256_vector(psk, 32, 2, addr, vlen, hash); clen = left > hashlen ? hashlen : left; os_memcpy(opos, hash, clen); opos += clen; left -= clen; } return 0; }
static int wps_build_e_hash(struct wps_data *wps, struct wpabuf *msg) { u8 *hash; const u8 *addr[4]; size_t len[4]; if (random_get_bytes(wps->snonce, 2 * WPS_SECRET_NONCE_LEN) < 0) return -1; wpa_hexdump(MSG_DEBUG, "WPS: E-S1", wps->snonce, WPS_SECRET_NONCE_LEN); wpa_hexdump(MSG_DEBUG, "WPS: E-S2", wps->snonce + WPS_SECRET_NONCE_LEN, WPS_SECRET_NONCE_LEN); if (wps->dh_pubkey_e == NULL || wps->dh_pubkey_r == NULL) { wpa_printf(MSG_DEBUG, "WPS: DH public keys not available for " "E-Hash derivation"); return -1; } wpa_printf(MSG_DEBUG, "WPS: * E-Hash1"); wpabuf_put_be16(msg, ATTR_E_HASH1); wpabuf_put_be16(msg, SHA256_MAC_LEN); hash = wpabuf_put(msg, SHA256_MAC_LEN); /* E-Hash1 = HMAC_AuthKey(E-S1 || PSK1 || PK_E || PK_R) */ addr[0] = wps->snonce; len[0] = WPS_SECRET_NONCE_LEN; addr[1] = wps->psk1; len[1] = WPS_PSK_LEN; addr[2] = wpabuf_head(wps->dh_pubkey_e); len[2] = wpabuf_len(wps->dh_pubkey_e); addr[3] = wpabuf_head(wps->dh_pubkey_r); len[3] = wpabuf_len(wps->dh_pubkey_r); hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); wpa_hexdump(MSG_DEBUG, "WPS: E-Hash1", hash, SHA256_MAC_LEN); wpa_printf(MSG_DEBUG, "WPS: * E-Hash2"); wpabuf_put_be16(msg, ATTR_E_HASH2); wpabuf_put_be16(msg, SHA256_MAC_LEN); hash = wpabuf_put(msg, SHA256_MAC_LEN); /* E-Hash2 = HMAC_AuthKey(E-S2 || PSK2 || PK_E || PK_R) */ addr[0] = wps->snonce + WPS_SECRET_NONCE_LEN; addr[1] = wps->psk2; hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); wpa_hexdump(MSG_DEBUG, "WPS: E-Hash2", hash, SHA256_MAC_LEN); return 0; }
/** * @brief Wrapper function for HMAC-SHA256 (RFC 2104) * * @param Key Key for HMAC operations * @param Key_size Length of the key in bytes * @param Message Pointers to the data areas * @param Message_len Lengths of the data blocks * @param Mac Buffer for the hash (32 bytes) * @param MacSize Length of hash buffer * @return 0 on success, -1 on failure */ int MrvHMAC_SHA256(const u8 * Key, u32 Key_size, u8 * Message, u32 Message_len, u8 * Mac, u32 MacSize) { const u8 *addr[2]; size_t len[2]; addr[0] = Message; len[0] = (size_t) Message_len; hmac_sha256_vector(Key, Key_size, 1, addr, len, Mac); return 0; }
static int eap_eke_prf_hmac_sha256(const u8 *key, size_t key_len, const u8 *data, size_t data_len, u8 *res, size_t len) { u8 hash[SHA256_MAC_LEN]; u8 idx; const u8 *addr[3]; size_t vlen[3]; int ret; idx = 0; addr[0] = hash; vlen[0] = SHA256_MAC_LEN; addr[1] = data; vlen[1] = data_len; addr[2] = &idx; vlen[2] = 1; while (len > 0) { idx++; if (idx == 1) ret = hmac_sha256_vector(key, key_len, 2, &addr[1], &vlen[1], hash); else ret = hmac_sha256_vector(key, key_len, 3, addr, vlen, hash); if (ret < 0) return -1; if (len > SHA256_MAC_LEN) { os_memcpy(res, hash, SHA256_MAC_LEN); res += SHA256_MAC_LEN; len -= SHA256_MAC_LEN; } else { os_memcpy(res, hash, len); len = 0; } } return 0; }
/** * rsn_pmkid_suite_b - Calculate PMK identifier for Suite B AKM * @kck: Key confirmation key * @kck_len: Length of kck in bytes * @aa: Authenticator address * @spa: Supplicant address * @pmkid: Buffer for PMKID * Returns: 0 on success, -1 on failure * * IEEE Std 802.11ac-2013 - 11.6.1.3 Pairwise key hierarchy * PMKID = Truncate(HMAC-SHA-256(KCK, "PMK Name" || AA || SPA)) */ int rsn_pmkid_suite_b(const u8 *kck, size_t kck_len, const u8 *aa, const u8 *spa, u8 *pmkid) { char *title = "PMK Name"; const u8 *addr[3]; const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN }; unsigned char hash[SHA256_MAC_LEN]; addr[0] = (u8 *) title; addr[1] = aa; addr[2] = spa; if (hmac_sha256_vector(kck, kck_len, 3, addr, len, hash) < 0) return -1; os_memcpy(pmkid, hash, PMKID_LEN); return 0; }
static void prf_prime(const u8 *k, const char *seed1, const u8 *seed2, size_t seed2_len, const u8 *seed3, size_t seed3_len, u8 *res, size_t res_len) { const u8 *addr[5]; size_t len[5]; u8 hash[SHA256_MAC_LEN]; u8 iter; /* * PRF'(K,S) = T1 | T2 | T3 | T4 | ... * T1 = HMAC-SHA-256 (K, S | 0x01) * T2 = HMAC-SHA-256 (K, T1 | S | 0x02) * T3 = HMAC-SHA-256 (K, T2 | S | 0x03) * T4 = HMAC-SHA-256 (K, T3 | S | 0x04) * ... */ addr[0] = hash; len[0] = 0; addr[1] = (const u8 *) seed1; len[1] = os_strlen(seed1); addr[2] = seed2; len[2] = seed2_len; addr[3] = seed3; len[3] = seed3_len; addr[4] = &iter; len[4] = 1; iter = 0; while (res_len) { size_t hlen; iter++; hmac_sha256_vector(k, 32, 5, addr, len, hash); len[0] = SHA256_MAC_LEN; hlen = res_len > SHA256_MAC_LEN ? SHA256_MAC_LEN : res_len; os_memcpy(res, hash, hlen); res += hlen; res_len -= hlen; } }
/** * rsn_pmkid - Calculate PMK identifier * @pmk: Pairwise master key * @pmk_len: Length of pmk in bytes * @aa: Authenticator address * @spa: Supplicant address * @pmkid: Buffer for PMKID * @use_sha256: Whether to use SHA256-based KDF * * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy * PMKID = HMAC-SHA1-128(PMK, "PMK Name" || AA || SPA) */ void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa, u8 *pmkid, int use_sha256) { char *title = "PMK Name"; const u8 *addr[3]; const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN }; unsigned char hash[SHA256_MAC_LEN]; addr[0] = (u8 *) title; addr[1] = aa; addr[2] = spa; #ifdef CONFIG_IEEE80211W if (use_sha256) hmac_sha256_vector(pmk, pmk_len, 3, addr, len, hash); else #endif /* CONFIG_IEEE80211W */ hmac_sha1_vector(pmk, pmk_len, 3, addr, len, hash); os_memcpy(pmkid, hash, PMKID_LEN); }
int eap_sim_verify_mac_sha256(const u8 *k_aut, const struct wpabuf *req, const u8 *mac, const u8 *extra, size_t extra_len) { unsigned char hmac[SHA256_MAC_LEN]; const u8 *addr[2]; size_t len[2]; u8 *tmp; if (mac == NULL || wpabuf_len(req) < EAP_SIM_MAC_LEN || mac < wpabuf_head_u8(req) || mac > wpabuf_head_u8(req) + wpabuf_len(req) - EAP_SIM_MAC_LEN) return -1; tmp = os_malloc(wpabuf_len(req)); if (tmp == NULL) return -1; addr[0] = tmp; len[0] = wpabuf_len(req); addr[1] = extra; len[1] = extra_len; /* HMAC-SHA-256-128 */ os_memcpy(tmp, wpabuf_head(req), wpabuf_len(req)); os_memset(tmp + (mac - wpabuf_head_u8(req)), 0, EAP_SIM_MAC_LEN); wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Verify MAC - msg", tmp, wpabuf_len(req)); wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Verify MAC - extra data", extra, extra_len); wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA': Verify MAC - K_aut", k_aut, EAP_AKA_PRIME_K_AUT_LEN); hmac_sha256_vector(k_aut, EAP_AKA_PRIME_K_AUT_LEN, 2, addr, len, hmac); wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Verify MAC: MAC", hmac, EAP_SIM_MAC_LEN); os_free(tmp); return (os_memcmp(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1; }
static int wps_process_r_snonce2(struct wps_data *wps, const u8 *r_snonce2) { u8 hash[SHA256_MAC_LEN]; const u8 *addr[4]; size_t len[4]; if (r_snonce2 == NULL) { wpa_printf(MSG_DEBUG, "WPS: No R-SNonce2 received"); return -1; } wpa_hexdump_key(MSG_DEBUG, "WPS: R-SNonce2", r_snonce2, WPS_SECRET_NONCE_LEN); /* R-Hash2 = HMAC_AuthKey(R-S2 || PSK2 || PK_E || PK_R) */ addr[0] = r_snonce2; len[0] = WPS_SECRET_NONCE_LEN; addr[1] = wps->psk2; len[1] = WPS_PSK_LEN; addr[2] = wpabuf_head(wps->dh_pubkey_e); len[2] = wpabuf_len(wps->dh_pubkey_e); addr[3] = wpabuf_head(wps->dh_pubkey_r); len[3] = wpabuf_len(wps->dh_pubkey_r); hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); if (os_memcmp(wps->peer_hash2, hash, WPS_HASH_LEN) != 0) { wpa_printf(MSG_DEBUG, "WPS: R-Hash2 derived from R-S2 does " "not match with the pre-committed value"); wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE; wps_pwd_auth_fail_event(wps->wps, 1, 2); return -1; } wpa_printf(MSG_DEBUG, "WPS: Registrar proved knowledge of the second " "half of the device password"); return 0; }
static int eap_eke_prf(u8 prf, const u8 *key, size_t key_len, const u8 *data, size_t data_len, const u8 *data2, size_t data2_len, u8 *res) { const u8 *addr[2]; size_t len[2]; size_t num_elem = 1; addr[0] = data; len[0] = data_len; if (data2) { num_elem++; addr[1] = data2; len[1] = data2_len; } if (prf == EAP_EKE_PRF_HMAC_SHA1) return hmac_sha1_vector(key, key_len, num_elem, addr, len, res); if (prf == EAP_EKE_PRF_HMAC_SHA2_256) return hmac_sha256_vector(key, key_len, num_elem, addr, len, res); return -1; }
void eap_sim_add_mac_sha256(const u8 *k_aut, const u8 *msg, size_t msg_len, u8 *mac, const u8 *extra, size_t extra_len) { unsigned char hmac[SHA256_MAC_LEN]; const u8 *addr[2]; size_t len[2]; addr[0] = msg; len[0] = msg_len; addr[1] = extra; len[1] = extra_len; /* HMAC-SHA-256-128 */ os_memset(mac, 0, EAP_SIM_MAC_LEN); wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Add MAC - msg", msg, msg_len); wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Add MAC - extra data", extra, extra_len); wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA': Add MAC - K_aut", k_aut, EAP_AKA_PRIME_K_AUT_LEN); hmac_sha256_vector(k_aut, EAP_AKA_PRIME_K_AUT_LEN, 2, addr, len, hmac); os_memcpy(mac, hmac, EAP_SIM_MAC_LEN); wpa_hexdump(MSG_MSGDUMP, "EAP-AKA': Add MAC: MAC", mac, EAP_SIM_MAC_LEN); }
/** * rsn_smkid - Derive SMK identifier * @smk: Station master key (32 bytes) * @pnonce: Peer Nonce * @mac_p: Peer MAC address * @inonce: Initiator Nonce * @mac_i: Initiator MAC address * @use_sha256: Whether to use SHA256-based KDF * * 8.5.1.4 Station to station (STK) key hierarchy * SMKID = HMAC-SHA1-128(SMK, "SMK Name" || PNonce || MAC_P || INonce || MAC_I) */ static void rsn_smkid(const u8 *smk, const u8 *pnonce, const u8 *mac_p, const u8 *inonce, const u8 *mac_i, u8 *smkid, int use_sha256) { char *title = "SMK Name"; const u8 *addr[5]; const size_t len[5] = { 8, WPA_NONCE_LEN, ETH_ALEN, WPA_NONCE_LEN, ETH_ALEN }; unsigned char hash[SHA256_MAC_LEN]; addr[0] = (u8 *) title; addr[1] = pnonce; addr[2] = mac_p; addr[3] = inonce; addr[4] = mac_i; #ifdef CONFIG_IEEE80211W if (use_sha256) hmac_sha256_vector(smk, PMK_LEN, 5, addr, len, hash); else #endif /* CONFIG_IEEE80211W */ hmac_sha1_vector(smk, PMK_LEN, 5, addr, len, hash); os_memcpy(smkid, hash, PMKID_LEN); }
void wps_kdf(const u8 *key, const u8 *label_prefix, size_t label_prefix_len, const char *label, u8 *res, size_t res_len) { u8 i_buf[4], key_bits[4]; const u8 *addr[4]; size_t len[4]; int i, iter; u8 hash[SHA256_MAC_LEN], *opos; size_t left; WPA_PUT_BE32(key_bits, res_len * 8); addr[0] = i_buf; len[0] = sizeof(i_buf); addr[1] = label_prefix; len[1] = label_prefix_len; addr[2] = (const u8 *) label; len[2] = os_strlen(label); addr[3] = key_bits; len[3] = sizeof(key_bits); iter = (res_len + SHA256_MAC_LEN - 1) / SHA256_MAC_LEN; opos = res; left = res_len; for (i = 1; i <= iter; i++) { WPA_PUT_BE32(i_buf, i); hmac_sha256_vector(key, SHA256_MAC_LEN, 4, addr, len, hash); if (i < iter) { os_memcpy(opos, hash, SHA256_MAC_LEN); opos += SHA256_MAC_LEN; left -= SHA256_MAC_LEN; } else os_memcpy(opos, hash, left); } }
int wps_derive_keys(struct wps_data *wps) { struct wpabuf *pubkey, *dh_shared; u8 dhkey[SHA256_MAC_LEN], kdk[SHA256_MAC_LEN]; const u8 *addr[3]; size_t len[3]; u8 keys[WPS_AUTHKEY_LEN + WPS_KEYWRAPKEY_LEN + WPS_EMSK_LEN]; if (wps->dh_privkey == NULL) { wpa_printf(MSG_DEBUG, "WPS: Own DH private key not available"); return -1; } pubkey = wps->registrar ? wps->dh_pubkey_e : wps->dh_pubkey_r; if (pubkey == NULL) { wpa_printf(MSG_DEBUG, "WPS: Peer DH public key not available"); return -1; } dh_shared = dh5_derive_shared(wps->dh_ctx, pubkey, wps->dh_privkey); dh5_free(wps->dh_ctx); wps->dh_ctx = NULL; dh_shared = wpabuf_zeropad(dh_shared, 192); if (dh_shared == NULL) { wpa_printf(MSG_DEBUG, "WPS: Failed to derive DH shared key"); return -1; } /* Own DH private key is not needed anymore */ wpabuf_free(wps->dh_privkey); wps->dh_privkey = NULL; wpa_hexdump_buf_key(MSG_DEBUG, "WPS: DH shared key", dh_shared); /* DHKey = SHA-256(g^AB mod p) */ addr[0] = wpabuf_head(dh_shared); len[0] = wpabuf_len(dh_shared); sha256_vector(1, addr, len, dhkey); wpa_hexdump_key(MSG_DEBUG, "WPS: DHKey", dhkey, sizeof(dhkey)); wpabuf_free(dh_shared); /* KDK = HMAC-SHA-256_DHKey(N1 || EnrolleeMAC || N2) */ addr[0] = wps->nonce_e; len[0] = WPS_NONCE_LEN; addr[1] = wps->mac_addr_e; len[1] = ETH_ALEN; addr[2] = wps->nonce_r; len[2] = WPS_NONCE_LEN; hmac_sha256_vector(dhkey, sizeof(dhkey), 3, addr, len, kdk); wpa_hexdump_key(MSG_DEBUG, "WPS: KDK", kdk, sizeof(kdk)); wps_kdf(kdk, NULL, 0, "Wi-Fi Easy and Secure Key Derivation", keys, sizeof(keys)); os_memcpy(wps->authkey, keys, WPS_AUTHKEY_LEN); os_memcpy(wps->keywrapkey, keys + WPS_AUTHKEY_LEN, WPS_KEYWRAPKEY_LEN); os_memcpy(wps->emsk, keys + WPS_AUTHKEY_LEN + WPS_KEYWRAPKEY_LEN, WPS_EMSK_LEN); wpa_hexdump_key(MSG_DEBUG, "WPS: AuthKey", wps->authkey, WPS_AUTHKEY_LEN); wpa_hexdump_key(MSG_DEBUG, "WPS: KeyWrapKey", wps->keywrapkey, WPS_KEYWRAPKEY_LEN); wpa_hexdump_key(MSG_DEBUG, "WPS: EMSK", wps->emsk, WPS_EMSK_LEN); /****** ADD THIS PART ******/ memset(pixie_authkey,0,sizeof(pixie_authkey)); if ( get_debug()==4 ) { //verbose (-vvv) printf("[P] AuthKey: "); } int pixiecnt = 0; for (; pixiecnt < WPS_AUTHKEY_LEN; pixiecnt++) { if ( get_debug()==4 ) { //verbose (-vvv) printf("%02x", wps->authkey[pixiecnt]); } sprintf(cmd_pixie_aux, "%02x", wps->authkey[pixiecnt]); strcat(pixie_authkey, cmd_pixie_aux); if (pixiecnt != WPS_AUTHKEY_LEN - 1) { if ( get_debug()==4 ) { //verbose (-vvv) printf(":"); } strcat(pixie_authkey,":"); } } if ( get_debug()==4 ) { //verbose (-vvv) printf("\n"); } /******/ return 0; }
int wps_derive_keys(struct wps_data *wps) { struct wpabuf *pubkey, *dh_shared; u8 dhkey[SHA256_MAC_LEN], kdk[SHA256_MAC_LEN]; const u8 *addr[3]; size_t len[3]; u8 keys[WPS_AUTHKEY_LEN + WPS_KEYWRAPKEY_LEN + WPS_EMSK_LEN]; if (wps->dh_privkey == NULL) { wpa_printf(MSG_DEBUG, "WPS: Own DH private key not available"); return -1; } pubkey = wps->registrar ? wps->dh_pubkey_e : wps->dh_pubkey_r; if (pubkey == NULL) { wpa_printf(MSG_DEBUG, "WPS: Peer DH public key not available"); return -1; } wpa_hexdump_buf_key(MSG_DEBUG, "WPS: DH Private Key", wps->dh_privkey); wpa_hexdump_buf(MSG_DEBUG, "WPS: DH peer Public Key", pubkey); dh_shared = dh5_derive_shared(wps->dh_ctx, pubkey, wps->dh_privkey); dh5_free(wps->dh_ctx); wps->dh_ctx = NULL; dh_shared = wpabuf_zeropad(dh_shared, 192); if (dh_shared == NULL) { wpa_printf(MSG_DEBUG, "WPS: Failed to derive DH shared key"); return -1; } /* Own DH private key is not needed anymore */ wpabuf_free(wps->dh_privkey); wps->dh_privkey = NULL; wpa_hexdump_buf_key(MSG_DEBUG, "WPS: DH shared key", dh_shared); /* DHKey = SHA-256(g^AB mod p) */ addr[0] = wpabuf_head(dh_shared); len[0] = wpabuf_len(dh_shared); sha256_vector(1, addr, len, dhkey); wpa_hexdump_key(MSG_DEBUG, "WPS: DHKey", dhkey, sizeof(dhkey)); wpabuf_free(dh_shared); /* KDK = HMAC-SHA-256_DHKey(N1 || EnrolleeMAC || N2) */ addr[0] = wps->nonce_e; len[0] = WPS_NONCE_LEN; addr[1] = wps->mac_addr_e; len[1] = ETH_ALEN; addr[2] = wps->nonce_r; len[2] = WPS_NONCE_LEN; hmac_sha256_vector(dhkey, sizeof(dhkey), 3, addr, len, kdk); wpa_hexdump_key(MSG_DEBUG, "WPS: KDK", kdk, sizeof(kdk)); wps_kdf(kdk, NULL, 0, "Wi-Fi Easy and Secure Key Derivation", keys, sizeof(keys)); os_memcpy(wps->authkey, keys, WPS_AUTHKEY_LEN); os_memcpy(wps->keywrapkey, keys + WPS_AUTHKEY_LEN, WPS_KEYWRAPKEY_LEN); os_memcpy(wps->emsk, keys + WPS_AUTHKEY_LEN + WPS_KEYWRAPKEY_LEN, WPS_EMSK_LEN); wpa_hexdump_key(MSG_DEBUG, "WPS: AuthKey", wps->authkey, WPS_AUTHKEY_LEN); wpa_hexdump_key(MSG_DEBUG, "WPS: KeyWrapKey", wps->keywrapkey, WPS_KEYWRAPKEY_LEN); wpa_hexdump_key(MSG_DEBUG, "WPS: EMSK", wps->emsk, WPS_EMSK_LEN); return 0; }
/** * hmac_sha256 - HMAC-SHA256 over data buffer (RFC 2104) * @key: Key for HMAC operations * @key_len: Length of the key in bytes * @data: Pointers to the data area * @data_len: Length of the data area * @mac: Buffer for the hash (20 bytes) */ void hmac_sha256(const u8 *key, size_t key_len, const u8 *data, size_t data_len, u8 *mac) { hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac); }
int main(int argc, char *argv[]) { unsigned int i; u8 hash[32]; const u8 *addr[2]; size_t len[2]; int errors = 0; for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { printf("SHA256 test case %d:", i + 1); addr[0] = (u8 *) tests[i].data; len[0] = strlen(tests[i].data); sha256_vector(1, addr, len, hash); if (memcmp(hash, tests[i].hash, 32) != 0) { printf(" FAIL"); errors++; } else printf(" OK"); if (len[0]) { addr[0] = (u8 *) tests[i].data; len[0] = 1; addr[1] = (u8 *) tests[i].data + 1; len[1] = strlen(tests[i].data) - 1; sha256_vector(2, addr, len, hash); if (memcmp(hash, tests[i].hash, 32) != 0) { printf(" FAIL"); errors++; } else printf(" OK"); } printf("\n"); } for (i = 0; i < sizeof(hmac_tests) / sizeof(hmac_tests[0]); i++) { struct hmac_test *t = &hmac_tests[i]; printf("HMAC-SHA256 test case %d:", i + 1); hmac_sha256(t->key, t->key_len, t->data, t->data_len, hash); if (memcmp(hash, t->hash, 32) != 0) { printf(" FAIL"); errors++; } else printf(" OK"); addr[0] = t->data; len[0] = t->data_len; hmac_sha256_vector(t->key, t->key_len, 1, addr, len, hash); if (memcmp(hash, t->hash, 32) != 0) { printf(" FAIL"); errors++; } else printf(" OK"); if (len[0]) { addr[0] = t->data; len[0] = 1; addr[1] = t->data + 1; len[1] = t->data_len - 1; hmac_sha256_vector(t->key, t->key_len, 2, addr, len, hash); if (memcmp(hash, t->hash, 32) != 0) { printf(" FAIL"); errors++; } else printf(" OK"); } printf("\n"); } printf("Test IEEE 802.11r KDF\n"); sha256_prf("abc", 3, "KDF test", "data", 4, hash, sizeof(hash)); /* TODO: add proper test case for this */ return errors; }
void eap_aka_prime_derive_ck_ik_prime(u8 *ck, u8 *ik, const u8 *sqn_ak, const u8 *network_name, size_t network_name_len) { u8 key[EAP_AKA_CK_LEN + EAP_AKA_IK_LEN]; u8 hash[SHA256_MAC_LEN]; const u8 *addr[5]; size_t len[5]; u8 fc; u8 l0[2], l1[2]; /* 3GPP TS 33.402 V8.0.0 * (CK', IK') = F(CK, IK, <access network identity>) */ /* TODO: CK', IK' generation should really be moved into the actual * AKA procedure with network name passed in there and option to use * AMF separation bit = 1 (3GPP TS 33.401). */ /* Change Request 33.402 CR 0033 to version 8.1.1 from * 3GPP TSG-SA WG3 Meeting #53 in September 2008: * * CK' || IK' = HMAC-SHA-256(Key, S) * S = FC || P0 || L0 || P1 || L1 || ... || Pn || Ln * Key = CK || IK * FC = 0x20 * P0 = access network identity (3GPP TS 24.302) * L0 = length of acceess network identity (2 octets, big endian) * P1 = SQN xor AK (if AK is not used, AK is treaded as 000..0 * L1 = 0x00 0x06 */ fc = 0x20; wpa_printf(MSG_DEBUG, "EAP-AKA': Derive (CK',IK') from (CK,IK)"); wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': CK", ck, EAP_AKA_CK_LEN); wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': IK", ik, EAP_AKA_IK_LEN); wpa_printf(MSG_DEBUG, "EAP-AKA': FC = 0x%x", fc); wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA': P0 = Access network identity", network_name, network_name_len); wpa_hexdump(MSG_DEBUG, "EAP-AKA': P1 = SQN xor AK", sqn_ak, 6); os_memcpy(key, ck, EAP_AKA_CK_LEN); os_memcpy(key + EAP_AKA_CK_LEN, ik, EAP_AKA_IK_LEN); wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': Key = CK || IK", key, sizeof(key)); addr[0] = &fc; len[0] = 1; addr[1] = network_name; len[1] = network_name_len; WPA_PUT_BE16(l0, network_name_len); addr[2] = l0; len[2] = 2; addr[3] = sqn_ak; len[3] = 6; WPA_PUT_BE16(l1, 6); addr[4] = l1; len[4] = 2; hmac_sha256_vector(key, sizeof(key), 5, addr, len, hash); wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': KDF output (CK' || IK')", hash, sizeof(hash)); os_memcpy(ck, hash, EAP_AKA_CK_LEN); os_memcpy(ik, hash + EAP_AKA_CK_LEN, EAP_AKA_IK_LEN); wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': CK'", ck, EAP_AKA_CK_LEN); wpa_hexdump_key(MSG_DEBUG, "EAP-AKA': IK'", ik, EAP_AKA_IK_LEN); }