2 * Wi-Fi Protected Setup - common functionality
3 * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
18 #include "dh_groups.h"
23 #include "wps_dev_attr.h"
26 void wps_kdf(const u8
*key
, const u8
*label_prefix
, size_t label_prefix_len
,
27 const char *label
, u8
*res
, size_t res_len
)
29 u8 i_buf
[4], key_bits
[4];
33 u8 hash
[SHA256_MAC_LEN
], *opos
;
36 WPA_PUT_BE32(key_bits
, res_len
* 8);
39 len
[0] = sizeof(i_buf
);
40 addr
[1] = label_prefix
;
41 len
[1] = label_prefix_len
;
42 addr
[2] = (const u8
*) label
;
43 len
[2] = os_strlen(label
);
45 len
[3] = sizeof(key_bits
);
47 iter
= (res_len
+ SHA256_MAC_LEN
- 1) / SHA256_MAC_LEN
;
51 for (i
= 1; i
<= iter
; i
++) {
52 WPA_PUT_BE32(i_buf
, i
);
53 hmac_sha256_vector(key
, SHA256_MAC_LEN
, 4, addr
, len
, hash
);
55 os_memcpy(opos
, hash
, SHA256_MAC_LEN
);
56 opos
+= SHA256_MAC_LEN
;
57 left
-= SHA256_MAC_LEN
;
59 os_memcpy(opos
, hash
, left
);
64 int wps_derive_keys(struct wps_data
*wps
)
66 struct wpabuf
*pubkey
, *dh_shared
;
67 u8 dhkey
[SHA256_MAC_LEN
], kdk
[SHA256_MAC_LEN
];
70 u8 keys
[WPS_AUTHKEY_LEN
+ WPS_KEYWRAPKEY_LEN
+ WPS_EMSK_LEN
];
72 if (wps
->dh_privkey
== NULL
) {
73 wpa_printf(MSG_DEBUG
, "WPS: Own DH private key not available");
77 pubkey
= wps
->registrar
? wps
->dh_pubkey_e
: wps
->dh_pubkey_r
;
79 wpa_printf(MSG_DEBUG
, "WPS: Peer DH public key not available");
83 dh_shared
= dh_derive_shared(pubkey
, wps
->dh_privkey
,
84 dh_groups_get(WPS_DH_GROUP
));
85 dh_shared
= wpabuf_zeropad(dh_shared
, 192);
86 if (dh_shared
== NULL
) {
87 wpa_printf(MSG_DEBUG
, "WPS: Failed to derive DH shared key");
91 /* Own DH private key is not needed anymore */
92 wpabuf_free(wps
->dh_privkey
);
93 wps
->dh_privkey
= NULL
;
95 wpa_hexdump_buf_key(MSG_DEBUG
, "WPS: DH shared key", dh_shared
);
97 /* DHKey = SHA-256(g^AB mod p) */
98 addr
[0] = wpabuf_head(dh_shared
);
99 len
[0] = wpabuf_len(dh_shared
);
100 sha256_vector(1, addr
, len
, dhkey
);
101 wpa_hexdump_key(MSG_DEBUG
, "WPS: DHKey", dhkey
, sizeof(dhkey
));
102 wpabuf_free(dh_shared
);
104 /* KDK = HMAC-SHA-256_DHKey(N1 || EnrolleeMAC || N2) */
105 addr
[0] = wps
->nonce_e
;
106 len
[0] = WPS_NONCE_LEN
;
107 addr
[1] = wps
->mac_addr_e
;
109 addr
[2] = wps
->nonce_r
;
110 len
[2] = WPS_NONCE_LEN
;
111 hmac_sha256_vector(dhkey
, sizeof(dhkey
), 3, addr
, len
, kdk
);
112 wpa_hexdump_key(MSG_DEBUG
, "WPS: KDK", kdk
, sizeof(kdk
));
114 wps_kdf(kdk
, NULL
, 0, "Wi-Fi Easy and Secure Key Derivation",
116 os_memcpy(wps
->authkey
, keys
, WPS_AUTHKEY_LEN
);
117 os_memcpy(wps
->keywrapkey
, keys
+ WPS_AUTHKEY_LEN
, WPS_KEYWRAPKEY_LEN
);
118 os_memcpy(wps
->emsk
, keys
+ WPS_AUTHKEY_LEN
+ WPS_KEYWRAPKEY_LEN
,
121 wpa_hexdump_key(MSG_DEBUG
, "WPS: AuthKey",
122 wps
->authkey
, WPS_AUTHKEY_LEN
);
123 wpa_hexdump_key(MSG_DEBUG
, "WPS: KeyWrapKey",
124 wps
->keywrapkey
, WPS_KEYWRAPKEY_LEN
);
125 wpa_hexdump_key(MSG_DEBUG
, "WPS: EMSK", wps
->emsk
, WPS_EMSK_LEN
);
131 void wps_derive_psk(struct wps_data
*wps
, const u8
*dev_passwd
,
132 size_t dev_passwd_len
)
134 u8 hash
[SHA256_MAC_LEN
];
136 hmac_sha256(wps
->authkey
, WPS_AUTHKEY_LEN
, dev_passwd
,
137 (dev_passwd_len
+ 1) / 2, hash
);
138 os_memcpy(wps
->psk1
, hash
, WPS_PSK_LEN
);
139 hmac_sha256(wps
->authkey
, WPS_AUTHKEY_LEN
,
140 dev_passwd
+ (dev_passwd_len
+ 1) / 2,
141 dev_passwd_len
/ 2, hash
);
142 os_memcpy(wps
->psk2
, hash
, WPS_PSK_LEN
);
144 wpa_hexdump_ascii_key(MSG_DEBUG
, "WPS: Device Password",
145 dev_passwd
, dev_passwd_len
);
146 wpa_hexdump_key(MSG_DEBUG
, "WPS: PSK1", wps
->psk1
, WPS_PSK_LEN
);
147 wpa_hexdump_key(MSG_DEBUG
, "WPS: PSK2", wps
->psk2
, WPS_PSK_LEN
);
151 struct wpabuf
* wps_decrypt_encr_settings(struct wps_data
*wps
, const u8
*encr
,
154 struct wpabuf
*decrypted
;
155 const size_t block_size
= 16;
161 if (encr
== NULL
|| encr_len
< 2 * block_size
|| encr_len
% block_size
)
163 wpa_printf(MSG_DEBUG
, "WPS: No Encrypted Settings received");
167 decrypted
= wpabuf_alloc(encr_len
- block_size
);
168 if (decrypted
== NULL
)
171 wpa_hexdump(MSG_MSGDUMP
, "WPS: Encrypted Settings", encr
, encr_len
);
172 wpabuf_put_data(decrypted
, encr
+ block_size
, encr_len
- block_size
);
173 if (aes_128_cbc_decrypt(wps
->keywrapkey
, encr
, wpabuf_mhead(decrypted
),
174 wpabuf_len(decrypted
))) {
175 wpabuf_free(decrypted
);
179 wpa_hexdump_buf_key(MSG_MSGDUMP
, "WPS: Decrypted Encrypted Settings",
182 pos
= wpabuf_head_u8(decrypted
) + wpabuf_len(decrypted
) - 1;
184 if (pad
> wpabuf_len(decrypted
)) {
185 wpa_printf(MSG_DEBUG
, "WPS: Invalid PKCS#5 v2.0 pad value");
186 wpabuf_free(decrypted
);
189 for (i
= 0; i
< pad
; i
++) {
191 wpa_printf(MSG_DEBUG
, "WPS: Invalid PKCS#5 v2.0 pad "
193 wpabuf_free(decrypted
);
197 decrypted
->used
-= pad
;
204 * wps_pin_checksum - Compute PIN checksum
205 * @pin: Seven digit PIN (i.e., eight digit PIN without the checksum digit)
206 * Returns: Checksum digit
208 unsigned int wps_pin_checksum(unsigned int pin
)
210 unsigned int accum
= 0;
212 accum
+= 3 * (pin
% 10);
218 return (10 - accum
% 10) % 10;
223 * wps_pin_valid - Check whether a PIN has a valid checksum
224 * @pin: Eight digit PIN (i.e., including the checksum digit)
225 * Returns: 1 if checksum digit is valid, or 0 if not
227 unsigned int wps_pin_valid(unsigned int pin
)
229 return wps_pin_checksum(pin
/ 10) == (pin
% 10);
234 * wps_generate_pin - Generate a random PIN
235 * Returns: Eight digit PIN (i.e., including the checksum digit)
237 unsigned int wps_generate_pin(void)
241 /* Generate seven random digits for the PIN */
242 if (os_get_random((unsigned char *) &val
, sizeof(val
)) < 0) {
245 val
= os_random() ^ now
.sec
^ now
.usec
;
249 /* Append checksum digit */
250 return val
* 10 + wps_pin_checksum(val
);
254 void wps_fail_event(struct wps_context
*wps
, enum wps_msg_type msg
)
256 union wps_event_data data
;
258 if (wps
->event_cb
== NULL
)
261 os_memset(&data
, 0, sizeof(data
));
263 wps
->event_cb(wps
->cb_ctx
, WPS_EV_FAIL
, &data
);
267 void wps_success_event(struct wps_context
*wps
)
269 if (wps
->event_cb
== NULL
)
272 wps
->event_cb(wps
->cb_ctx
, WPS_EV_SUCCESS
, NULL
);
276 void wps_pwd_auth_fail_event(struct wps_context
*wps
, int enrollee
, int part
)
278 union wps_event_data data
;
280 if (wps
->event_cb
== NULL
)
283 os_memset(&data
, 0, sizeof(data
));
284 data
.pwd_auth_fail
.enrollee
= enrollee
;
285 data
.pwd_auth_fail
.part
= part
;
286 wps
->event_cb(wps
->cb_ctx
, WPS_EV_PWD_AUTH_FAIL
, &data
);
290 void wps_pbc_overlap_event(struct wps_context
*wps
)
292 if (wps
->event_cb
== NULL
)
295 wps
->event_cb(wps
->cb_ctx
, WPS_EV_PBC_OVERLAP
, NULL
);
299 void wps_pbc_timeout_event(struct wps_context
*wps
)
301 if (wps
->event_cb
== NULL
)
304 wps
->event_cb(wps
->cb_ctx
, WPS_EV_PBC_TIMEOUT
, NULL
);