1189251Ssam/*
2189251Ssam * EAP-PEAP common routines
3252726Srpaulo * Copyright (c) 2008-2011, Jouni Malinen <j@w1.fi>
4189251Ssam *
5252726Srpaulo * This software may be distributed under the terms of the BSD license.
6252726Srpaulo * See README for more details.
7189251Ssam */
8189251Ssam
9189251Ssam#include "includes.h"
10189251Ssam
11189251Ssam#include "common.h"
12214734Srpaulo#include "crypto/sha1.h"
13189251Ssam#include "eap_peap_common.h"
14189251Ssam
15252726Srpauloint peap_prfplus(int version, const u8 *key, size_t key_len,
16252726Srpaulo		 const char *label, const u8 *seed, size_t seed_len,
17252726Srpaulo		 u8 *buf, size_t buf_len)
18189251Ssam{
19189251Ssam	unsigned char counter = 0;
20189251Ssam	size_t pos, plen;
21189251Ssam	u8 hash[SHA1_MAC_LEN];
22189251Ssam	size_t label_len = os_strlen(label);
23189251Ssam	u8 extra[2];
24189251Ssam	const unsigned char *addr[5];
25189251Ssam	size_t len[5];
26189251Ssam
27189251Ssam	addr[0] = hash;
28189251Ssam	len[0] = 0;
29189251Ssam	addr[1] = (unsigned char *) label;
30189251Ssam	len[1] = label_len;
31189251Ssam	addr[2] = seed;
32189251Ssam	len[2] = seed_len;
33189251Ssam
34189251Ssam	if (version == 0) {
35189251Ssam		/*
36189251Ssam		 * PRF+(K, S, LEN) = T1 | T2 | ... | Tn
37189251Ssam		 * T1 = HMAC-SHA1(K, S | 0x01 | 0x00 | 0x00)
38189251Ssam		 * T2 = HMAC-SHA1(K, T1 | S | 0x02 | 0x00 | 0x00)
39189251Ssam		 * ...
40189251Ssam		 * Tn = HMAC-SHA1(K, Tn-1 | S | n | 0x00 | 0x00)
41189251Ssam		 */
42189251Ssam
43189251Ssam		extra[0] = 0;
44189251Ssam		extra[1] = 0;
45189251Ssam
46189251Ssam		addr[3] = &counter;
47189251Ssam		len[3] = 1;
48189251Ssam		addr[4] = extra;
49189251Ssam		len[4] = 2;
50189251Ssam	} else {
51189251Ssam		/*
52189251Ssam		 * PRF (K,S,LEN) = T1 | T2 | T3 | T4 | ... where:
53189251Ssam		 * T1 = HMAC-SHA1(K, S | LEN | 0x01)
54189251Ssam		 * T2 = HMAC-SHA1 (K, T1 | S | LEN | 0x02)
55189251Ssam		 * T3 = HMAC-SHA1 (K, T2 | S | LEN | 0x03)
56189251Ssam		 * T4 = HMAC-SHA1 (K, T3 | S | LEN | 0x04)
57189251Ssam		 *   ...
58189251Ssam		 */
59189251Ssam
60189251Ssam		extra[0] = buf_len & 0xff;
61189251Ssam
62189251Ssam		addr[3] = extra;
63189251Ssam		len[3] = 1;
64189251Ssam		addr[4] = &counter;
65189251Ssam		len[4] = 1;
66189251Ssam	}
67189251Ssam
68189251Ssam	pos = 0;
69189251Ssam	while (pos < buf_len) {
70189251Ssam		counter++;
71189251Ssam		plen = buf_len - pos;
72252726Srpaulo		if (hmac_sha1_vector(key, key_len, 5, addr, len, hash) < 0)
73252726Srpaulo			return -1;
74189251Ssam		if (plen >= SHA1_MAC_LEN) {
75189251Ssam			os_memcpy(&buf[pos], hash, SHA1_MAC_LEN);
76189251Ssam			pos += SHA1_MAC_LEN;
77189251Ssam		} else {
78189251Ssam			os_memcpy(&buf[pos], hash, plen);
79189251Ssam			break;
80189251Ssam		}
81189251Ssam		len[0] = SHA1_MAC_LEN;
82189251Ssam	}
83252726Srpaulo
84252726Srpaulo	return 0;
85189251Ssam}
86