1/*
2 * EAP-PEAP common routines
3 * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
11 *
12 * See README and COPYING for more details.
13 */
14
15#include "includes.h"
16
17#include "common.h"
18#include "crypto/sha1.h"
19#include "eap_peap_common.h"
20
21void peap_prfplus(int version, const u8 *key, size_t key_len,
22		  const char *label, const u8 *seed, size_t seed_len,
23		  u8 *buf, size_t buf_len)
24{
25	unsigned char counter = 0;
26	size_t pos, plen;
27	u8 hash[SHA1_MAC_LEN];
28	size_t label_len = os_strlen(label);
29	u8 extra[2];
30	const unsigned char *addr[5];
31	size_t len[5];
32
33	addr[0] = hash;
34	len[0] = 0;
35	addr[1] = (unsigned char *) label;
36	len[1] = label_len;
37	addr[2] = seed;
38	len[2] = seed_len;
39
40	if (version == 0) {
41		/*
42		 * PRF+(K, S, LEN) = T1 | T2 | ... | Tn
43		 * T1 = HMAC-SHA1(K, S | 0x01 | 0x00 | 0x00)
44		 * T2 = HMAC-SHA1(K, T1 | S | 0x02 | 0x00 | 0x00)
45		 * ...
46		 * Tn = HMAC-SHA1(K, Tn-1 | S | n | 0x00 | 0x00)
47		 */
48
49		extra[0] = 0;
50		extra[1] = 0;
51
52		addr[3] = &counter;
53		len[3] = 1;
54		addr[4] = extra;
55		len[4] = 2;
56	} else {
57		/*
58		 * PRF (K,S,LEN) = T1 | T2 | T3 | T4 | ... where:
59		 * T1 = HMAC-SHA1(K, S | LEN | 0x01)
60		 * T2 = HMAC-SHA1 (K, T1 | S | LEN | 0x02)
61		 * T3 = HMAC-SHA1 (K, T2 | S | LEN | 0x03)
62		 * T4 = HMAC-SHA1 (K, T3 | S | LEN | 0x04)
63		 *   ...
64		 */
65
66		extra[0] = buf_len & 0xff;
67
68		addr[3] = extra;
69		len[3] = 1;
70		addr[4] = &counter;
71		len[4] = 1;
72	}
73
74	pos = 0;
75	while (pos < buf_len) {
76		counter++;
77		plen = buf_len - pos;
78		hmac_sha1_vector(key, key_len, 5, addr, len, hash);
79		if (plen >= SHA1_MAC_LEN) {
80			os_memcpy(&buf[pos], hash, SHA1_MAC_LEN);
81			pos += SHA1_MAC_LEN;
82		} else {
83			os_memcpy(&buf[pos], hash, plen);
84			break;
85		}
86		len[0] = SHA1_MAC_LEN;
87	}
88}
89