1e5b75505Sopenharmony_ci/*
2e5b75505Sopenharmony_ci * SHA1-based PRF
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#include "crypto.h"
14e5b75505Sopenharmony_ci
15e5b75505Sopenharmony_ci
16e5b75505Sopenharmony_ci/**
17e5b75505Sopenharmony_ci * sha1_prf - SHA1-based Pseudo-Random Function (PRF) (IEEE 802.11i, 8.5.1.1)
18e5b75505Sopenharmony_ci * @key: Key for PRF
19e5b75505Sopenharmony_ci * @key_len: Length of the key in bytes
20e5b75505Sopenharmony_ci * @label: A unique label for each purpose of the PRF
21e5b75505Sopenharmony_ci * @data: Extra data to bind into the key
22e5b75505Sopenharmony_ci * @data_len: Length of the data
23e5b75505Sopenharmony_ci * @buf: Buffer for the generated pseudo-random key
24e5b75505Sopenharmony_ci * @buf_len: Number of bytes of key to generate
25e5b75505Sopenharmony_ci * Returns: 0 on success, -1 of failure
26e5b75505Sopenharmony_ci *
27e5b75505Sopenharmony_ci * This function is used to derive new, cryptographically separate keys from a
28e5b75505Sopenharmony_ci * given key (e.g., PMK in IEEE 802.11i).
29e5b75505Sopenharmony_ci */
30e5b75505Sopenharmony_ciint sha1_prf(const u8 *key, size_t key_len, const char *label,
31e5b75505Sopenharmony_ci	     const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
32e5b75505Sopenharmony_ci{
33e5b75505Sopenharmony_ci	u8 counter = 0;
34e5b75505Sopenharmony_ci	size_t pos, plen;
35e5b75505Sopenharmony_ci	u8 hash[SHA1_MAC_LEN];
36e5b75505Sopenharmony_ci	size_t label_len = os_strlen(label) + 1;
37e5b75505Sopenharmony_ci	const unsigned char *addr[3];
38e5b75505Sopenharmony_ci	size_t len[3];
39e5b75505Sopenharmony_ci
40e5b75505Sopenharmony_ci	addr[0] = (u8 *) label;
41e5b75505Sopenharmony_ci	len[0] = label_len;
42e5b75505Sopenharmony_ci	addr[1] = data;
43e5b75505Sopenharmony_ci	len[1] = data_len;
44e5b75505Sopenharmony_ci	addr[2] = &counter;
45e5b75505Sopenharmony_ci	len[2] = 1;
46e5b75505Sopenharmony_ci
47e5b75505Sopenharmony_ci	pos = 0;
48e5b75505Sopenharmony_ci	while (pos < buf_len) {
49e5b75505Sopenharmony_ci		plen = buf_len - pos;
50e5b75505Sopenharmony_ci		if (plen >= SHA1_MAC_LEN) {
51e5b75505Sopenharmony_ci			if (hmac_sha1_vector(key, key_len, 3, addr, len,
52e5b75505Sopenharmony_ci					     &buf[pos]))
53e5b75505Sopenharmony_ci				return -1;
54e5b75505Sopenharmony_ci			pos += SHA1_MAC_LEN;
55e5b75505Sopenharmony_ci		} else {
56e5b75505Sopenharmony_ci			if (hmac_sha1_vector(key, key_len, 3, addr, len,
57e5b75505Sopenharmony_ci					     hash))
58e5b75505Sopenharmony_ci				return -1;
59e5b75505Sopenharmony_ci			os_memcpy(&buf[pos], hash, plen);
60e5b75505Sopenharmony_ci			break;
61e5b75505Sopenharmony_ci		}
62e5b75505Sopenharmony_ci		counter++;
63e5b75505Sopenharmony_ci	}
64e5b75505Sopenharmony_ci	forced_memzero(hash, sizeof(hash));
65e5b75505Sopenharmony_ci
66e5b75505Sopenharmony_ci	return 0;
67e5b75505Sopenharmony_ci}
68