1252190Srpaulo/*
2252190Srpaulo * SHA1-based PRF
3252190Srpaulo * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
4252190Srpaulo *
5252190Srpaulo * This software may be distributed under the terms of the BSD license.
6252190Srpaulo * See README for more details.
7252190Srpaulo */
8252190Srpaulo
9252190Srpaulo#include "includes.h"
10252190Srpaulo
11252190Srpaulo#include "common.h"
12252190Srpaulo#include "sha1.h"
13252190Srpaulo#include "crypto.h"
14252190Srpaulo
15252190Srpaulo
16252190Srpaulo/**
17252190Srpaulo * sha1_prf - SHA1-based Pseudo-Random Function (PRF) (IEEE 802.11i, 8.5.1.1)
18252190Srpaulo * @key: Key for PRF
19252190Srpaulo * @key_len: Length of the key in bytes
20252190Srpaulo * @label: A unique label for each purpose of the PRF
21252190Srpaulo * @data: Extra data to bind into the key
22252190Srpaulo * @data_len: Length of the data
23252190Srpaulo * @buf: Buffer for the generated pseudo-random key
24252190Srpaulo * @buf_len: Number of bytes of key to generate
25252190Srpaulo * Returns: 0 on success, -1 of failure
26252190Srpaulo *
27252190Srpaulo * This function is used to derive new, cryptographically separate keys from a
28252190Srpaulo * given key (e.g., PMK in IEEE 802.11i).
29252190Srpaulo */
30252190Srpauloint sha1_prf(const u8 *key, size_t key_len, const char *label,
31252190Srpaulo	     const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
32252190Srpaulo{
33252190Srpaulo	u8 counter = 0;
34252190Srpaulo	size_t pos, plen;
35252190Srpaulo	u8 hash[SHA1_MAC_LEN];
36252190Srpaulo	size_t label_len = os_strlen(label) + 1;
37252190Srpaulo	const unsigned char *addr[3];
38252190Srpaulo	size_t len[3];
39252190Srpaulo
40252190Srpaulo	addr[0] = (u8 *) label;
41252190Srpaulo	len[0] = label_len;
42252190Srpaulo	addr[1] = data;
43252190Srpaulo	len[1] = data_len;
44252190Srpaulo	addr[2] = &counter;
45252190Srpaulo	len[2] = 1;
46252190Srpaulo
47252190Srpaulo	pos = 0;
48252190Srpaulo	while (pos < buf_len) {
49252190Srpaulo		plen = buf_len - pos;
50252190Srpaulo		if (plen >= SHA1_MAC_LEN) {
51252190Srpaulo			if (hmac_sha1_vector(key, key_len, 3, addr, len,
52252190Srpaulo					     &buf[pos]))
53252190Srpaulo				return -1;
54252190Srpaulo			pos += SHA1_MAC_LEN;
55252190Srpaulo		} else {
56252190Srpaulo			if (hmac_sha1_vector(key, key_len, 3, addr, len,
57252190Srpaulo					     hash))
58252190Srpaulo				return -1;
59252190Srpaulo			os_memcpy(&buf[pos], hash, plen);
60252190Srpaulo			break;
61252190Srpaulo		}
62252190Srpaulo		counter++;
63252190Srpaulo	}
64351611Scy	forced_memzero(hash, sizeof(hash));
65252190Srpaulo
66252190Srpaulo	return 0;
67252190Srpaulo}
68