1e5b75505Sopenharmony_ci/* 2e5b75505Sopenharmony_ci * SHA1-based key derivation function (PBKDF2) for IEEE 802.11i 3e5b75505Sopenharmony_ci * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi> 4e5b75505Sopenharmony_ci * 5e5b75505Sopenharmony_ci * This software may be distributed under the terms of the BSD license. 6e5b75505Sopenharmony_ci * See README for more details. 7e5b75505Sopenharmony_ci */ 8e5b75505Sopenharmony_ci 9e5b75505Sopenharmony_ci#include "includes.h" 10e5b75505Sopenharmony_ci 11e5b75505Sopenharmony_ci#include "common.h" 12e5b75505Sopenharmony_ci#include "sha1.h" 13e5b75505Sopenharmony_ci 14e5b75505Sopenharmony_cistatic int pbkdf2_sha1_f(const char *passphrase, const u8 *ssid, 15e5b75505Sopenharmony_ci size_t ssid_len, int iterations, unsigned int count, 16e5b75505Sopenharmony_ci u8 *digest) 17e5b75505Sopenharmony_ci{ 18e5b75505Sopenharmony_ci unsigned char tmp[SHA1_MAC_LEN], tmp2[SHA1_MAC_LEN]; 19e5b75505Sopenharmony_ci int i, j; 20e5b75505Sopenharmony_ci unsigned char count_buf[4]; 21e5b75505Sopenharmony_ci const u8 *addr[2]; 22e5b75505Sopenharmony_ci size_t len[2]; 23e5b75505Sopenharmony_ci size_t passphrase_len = os_strlen(passphrase); 24e5b75505Sopenharmony_ci 25e5b75505Sopenharmony_ci addr[0] = ssid; 26e5b75505Sopenharmony_ci len[0] = ssid_len; 27e5b75505Sopenharmony_ci addr[1] = count_buf; 28e5b75505Sopenharmony_ci len[1] = 4; 29e5b75505Sopenharmony_ci 30e5b75505Sopenharmony_ci /* F(P, S, c, i) = U1 xor U2 xor ... Uc 31e5b75505Sopenharmony_ci * U1 = PRF(P, S || i) 32e5b75505Sopenharmony_ci * U2 = PRF(P, U1) 33e5b75505Sopenharmony_ci * Uc = PRF(P, Uc-1) 34e5b75505Sopenharmony_ci */ 35e5b75505Sopenharmony_ci 36e5b75505Sopenharmony_ci count_buf[0] = (count >> 24) & 0xff; 37e5b75505Sopenharmony_ci count_buf[1] = (count >> 16) & 0xff; 38e5b75505Sopenharmony_ci count_buf[2] = (count >> 8) & 0xff; 39e5b75505Sopenharmony_ci count_buf[3] = count & 0xff; 40e5b75505Sopenharmony_ci if (hmac_sha1_vector((u8 *) passphrase, passphrase_len, 2, addr, len, 41e5b75505Sopenharmony_ci tmp)) 42e5b75505Sopenharmony_ci return -1; 43e5b75505Sopenharmony_ci os_memcpy(digest, tmp, SHA1_MAC_LEN); 44e5b75505Sopenharmony_ci 45e5b75505Sopenharmony_ci for (i = 1; i < iterations; i++) { 46e5b75505Sopenharmony_ci if (hmac_sha1((u8 *) passphrase, passphrase_len, tmp, 47e5b75505Sopenharmony_ci SHA1_MAC_LEN, tmp2)) 48e5b75505Sopenharmony_ci return -1; 49e5b75505Sopenharmony_ci os_memcpy(tmp, tmp2, SHA1_MAC_LEN); 50e5b75505Sopenharmony_ci for (j = 0; j < SHA1_MAC_LEN; j++) 51e5b75505Sopenharmony_ci digest[j] ^= tmp2[j]; 52e5b75505Sopenharmony_ci } 53e5b75505Sopenharmony_ci 54e5b75505Sopenharmony_ci return 0; 55e5b75505Sopenharmony_ci} 56e5b75505Sopenharmony_ci 57e5b75505Sopenharmony_ci 58e5b75505Sopenharmony_ci/** 59e5b75505Sopenharmony_ci * pbkdf2_sha1 - SHA1-based key derivation function (PBKDF2) for IEEE 802.11i 60e5b75505Sopenharmony_ci * @passphrase: ASCII passphrase 61e5b75505Sopenharmony_ci * @ssid: SSID 62e5b75505Sopenharmony_ci * @ssid_len: SSID length in bytes 63e5b75505Sopenharmony_ci * @iterations: Number of iterations to run 64e5b75505Sopenharmony_ci * @buf: Buffer for the generated key 65e5b75505Sopenharmony_ci * @buflen: Length of the buffer in bytes 66e5b75505Sopenharmony_ci * Returns: 0 on success, -1 of failure 67e5b75505Sopenharmony_ci * 68e5b75505Sopenharmony_ci * This function is used to derive PSK for WPA-PSK. For this protocol, 69e5b75505Sopenharmony_ci * iterations is set to 4096 and buflen to 32. This function is described in 70e5b75505Sopenharmony_ci * IEEE Std 802.11-2004, Clause H.4. The main construction is from PKCS#5 v2.0. 71e5b75505Sopenharmony_ci */ 72e5b75505Sopenharmony_ci__attribute__ ((visibility ("default"))) int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len, 73e5b75505Sopenharmony_ci int iterations, u8 *buf, size_t buflen) 74e5b75505Sopenharmony_ci{ 75e5b75505Sopenharmony_ci unsigned int count = 0; 76e5b75505Sopenharmony_ci unsigned char *pos = buf; 77e5b75505Sopenharmony_ci size_t left = buflen, plen; 78e5b75505Sopenharmony_ci unsigned char digest[SHA1_MAC_LEN]; 79e5b75505Sopenharmony_ci 80e5b75505Sopenharmony_ci while (left > 0) { 81e5b75505Sopenharmony_ci count++; 82e5b75505Sopenharmony_ci if (pbkdf2_sha1_f(passphrase, ssid, ssid_len, iterations, 83e5b75505Sopenharmony_ci count, digest)) 84e5b75505Sopenharmony_ci return -1; 85e5b75505Sopenharmony_ci plen = left > SHA1_MAC_LEN ? SHA1_MAC_LEN : left; 86e5b75505Sopenharmony_ci os_memcpy(pos, digest, plen); 87e5b75505Sopenharmony_ci pos += plen; 88e5b75505Sopenharmony_ci left -= plen; 89e5b75505Sopenharmony_ci } 90e5b75505Sopenharmony_ci 91e5b75505Sopenharmony_ci return 0; 92e5b75505Sopenharmony_ci} 93