1214501Srpaulo/* 2214501Srpaulo * SHA1-based key derivation function (PBKDF2) for IEEE 802.11i 3214501Srpaulo * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi> 4214501Srpaulo * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7214501Srpaulo */ 8214501Srpaulo 9214501Srpaulo#include "includes.h" 10214501Srpaulo 11214501Srpaulo#include "common.h" 12214501Srpaulo#include "sha1.h" 13214501Srpaulo 14252726Srpaulostatic int pbkdf2_sha1_f(const char *passphrase, const u8 *ssid, 15214501Srpaulo size_t ssid_len, int iterations, unsigned int count, 16214501Srpaulo u8 *digest) 17214501Srpaulo{ 18214501Srpaulo unsigned char tmp[SHA1_MAC_LEN], tmp2[SHA1_MAC_LEN]; 19214501Srpaulo int i, j; 20214501Srpaulo unsigned char count_buf[4]; 21214501Srpaulo const u8 *addr[2]; 22214501Srpaulo size_t len[2]; 23214501Srpaulo size_t passphrase_len = os_strlen(passphrase); 24214501Srpaulo 25252726Srpaulo addr[0] = ssid; 26214501Srpaulo len[0] = ssid_len; 27214501Srpaulo addr[1] = count_buf; 28214501Srpaulo len[1] = 4; 29214501Srpaulo 30214501Srpaulo /* F(P, S, c, i) = U1 xor U2 xor ... Uc 31214501Srpaulo * U1 = PRF(P, S || i) 32214501Srpaulo * U2 = PRF(P, U1) 33214501Srpaulo * Uc = PRF(P, Uc-1) 34214501Srpaulo */ 35214501Srpaulo 36214501Srpaulo count_buf[0] = (count >> 24) & 0xff; 37214501Srpaulo count_buf[1] = (count >> 16) & 0xff; 38214501Srpaulo count_buf[2] = (count >> 8) & 0xff; 39214501Srpaulo count_buf[3] = count & 0xff; 40214501Srpaulo if (hmac_sha1_vector((u8 *) passphrase, passphrase_len, 2, addr, len, 41214501Srpaulo tmp)) 42214501Srpaulo return -1; 43214501Srpaulo os_memcpy(digest, tmp, SHA1_MAC_LEN); 44214501Srpaulo 45214501Srpaulo for (i = 1; i < iterations; i++) { 46214501Srpaulo if (hmac_sha1((u8 *) passphrase, passphrase_len, tmp, 47214501Srpaulo SHA1_MAC_LEN, tmp2)) 48214501Srpaulo return -1; 49214501Srpaulo os_memcpy(tmp, tmp2, SHA1_MAC_LEN); 50214501Srpaulo for (j = 0; j < SHA1_MAC_LEN; j++) 51214501Srpaulo digest[j] ^= tmp2[j]; 52214501Srpaulo } 53214501Srpaulo 54214501Srpaulo return 0; 55214501Srpaulo} 56214501Srpaulo 57214501Srpaulo 58214501Srpaulo/** 59214501Srpaulo * pbkdf2_sha1 - SHA1-based key derivation function (PBKDF2) for IEEE 802.11i 60214501Srpaulo * @passphrase: ASCII passphrase 61214501Srpaulo * @ssid: SSID 62214501Srpaulo * @ssid_len: SSID length in bytes 63214501Srpaulo * @iterations: Number of iterations to run 64214501Srpaulo * @buf: Buffer for the generated key 65214501Srpaulo * @buflen: Length of the buffer in bytes 66214501Srpaulo * Returns: 0 on success, -1 of failure 67214501Srpaulo * 68214501Srpaulo * This function is used to derive PSK for WPA-PSK. For this protocol, 69214501Srpaulo * iterations is set to 4096 and buflen to 32. This function is described in 70214501Srpaulo * IEEE Std 802.11-2004, Clause H.4. The main construction is from PKCS#5 v2.0. 71214501Srpaulo */ 72252726Srpauloint pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len, 73214501Srpaulo int iterations, u8 *buf, size_t buflen) 74214501Srpaulo{ 75214501Srpaulo unsigned int count = 0; 76214501Srpaulo unsigned char *pos = buf; 77214501Srpaulo size_t left = buflen, plen; 78214501Srpaulo unsigned char digest[SHA1_MAC_LEN]; 79214501Srpaulo 80214501Srpaulo while (left > 0) { 81214501Srpaulo count++; 82214501Srpaulo if (pbkdf2_sha1_f(passphrase, ssid, ssid_len, iterations, 83214501Srpaulo count, digest)) 84214501Srpaulo return -1; 85214501Srpaulo plen = left > SHA1_MAC_LEN ? SHA1_MAC_LEN : left; 86214501Srpaulo os_memcpy(pos, digest, plen); 87214501Srpaulo pos += plen; 88214501Srpaulo left -= plen; 89214501Srpaulo } 90214501Srpaulo 91214501Srpaulo return 0; 92214501Srpaulo} 93