1341618Scy/*
2341618Scy * FIPS 186-2 PRF for libcrypto
3341618Scy * Copyright (c) 2004-2017, Jouni Malinen <j@w1.fi>
4341618Scy *
5341618Scy * This software may be distributed under the terms of the BSD license.
6341618Scy * See README for more details.
7341618Scy */
8341618Scy
9341618Scy#include "includes.h"
10341618Scy#include <wolfssl/options.h>
11341618Scy#include <wolfssl/wolfcrypt/sha.h>
12341618Scy
13341618Scy#include "common.h"
14341618Scy#include "crypto.h"
15341618Scy
16341618Scy
17341618Scystatic void sha1_transform(u32 *state, const u8 data[64])
18341618Scy{
19341618Scy	wc_Sha sha;
20341618Scy
21341618Scy	os_memset(&sha, 0, sizeof(sha));
22341618Scy	sha.digest[0] = state[0];
23341618Scy	sha.digest[1] = state[1];
24341618Scy	sha.digest[2] = state[2];
25341618Scy	sha.digest[3] = state[3];
26341618Scy	sha.digest[4] = state[4];
27341618Scy	wc_ShaUpdate(&sha, data, 64);
28341618Scy	state[0] = sha.digest[0];
29341618Scy	state[1] = sha.digest[1];
30341618Scy	state[2] = sha.digest[2];
31341618Scy	state[3] = sha.digest[3];
32341618Scy	state[4] = sha.digest[4];
33341618Scy}
34341618Scy
35341618Scy
36341618Scyint fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
37341618Scy{
38341618Scy	u8 xkey[64];
39341618Scy	u32 t[5], _t[5];
40341618Scy	int i, j, m, k;
41341618Scy	u8 *xpos = x;
42341618Scy	u32 carry;
43341618Scy
44341618Scy	if (seed_len < sizeof(xkey))
45341618Scy		os_memset(xkey + seed_len, 0, sizeof(xkey) - seed_len);
46341618Scy	else
47341618Scy		seed_len = sizeof(xkey);
48341618Scy
49341618Scy	/* FIPS 186-2 + change notice 1 */
50341618Scy
51341618Scy	os_memcpy(xkey, seed, seed_len);
52341618Scy	t[0] = 0x67452301;
53341618Scy	t[1] = 0xEFCDAB89;
54341618Scy	t[2] = 0x98BADCFE;
55341618Scy	t[3] = 0x10325476;
56341618Scy	t[4] = 0xC3D2E1F0;
57341618Scy
58341618Scy	m = xlen / 40;
59341618Scy	for (j = 0; j < m; j++) {
60341618Scy		/* XSEED_j = 0 */
61341618Scy		for (i = 0; i < 2; i++) {
62341618Scy			/* XVAL = (XKEY + XSEED_j) mod 2^b */
63341618Scy
64341618Scy			/* w_i = G(t, XVAL) */
65341618Scy			os_memcpy(_t, t, 20);
66341618Scy			sha1_transform(_t, xkey);
67341618Scy			WPA_PUT_BE32(xpos, _t[0]);
68341618Scy			WPA_PUT_BE32(xpos + 4, _t[1]);
69341618Scy			WPA_PUT_BE32(xpos + 8, _t[2]);
70341618Scy			WPA_PUT_BE32(xpos + 12, _t[3]);
71341618Scy			WPA_PUT_BE32(xpos + 16, _t[4]);
72341618Scy
73341618Scy			/* XKEY = (1 + XKEY + w_i) mod 2^b */
74341618Scy			carry = 1;
75341618Scy			for (k = 19; k >= 0; k--) {
76341618Scy				carry += xkey[k] + xpos[k];
77341618Scy				xkey[k] = carry & 0xff;
78341618Scy				carry >>= 8;
79341618Scy			}
80341618Scy
81341618Scy			xpos += 20;
82341618Scy		}
83341618Scy		/* x_j = w_0|w_1 */
84341618Scy	}
85341618Scy
86341618Scy	return 0;
87341618Scy}
88