xref: /freebsd/contrib/wpa/src/crypto/sha1-tlsprf.c (revision c5c3ba6b43cac20dc9432eac15758d41cb2b8b1f)
1e28a4053SRui Paulo /*
2e28a4053SRui Paulo  * TLS PRF (SHA1 + MD5)
3e28a4053SRui Paulo  * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
4e28a4053SRui Paulo  *
5f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo  * See README for more details.
7e28a4053SRui Paulo  */
8e28a4053SRui Paulo 
9e28a4053SRui Paulo #include "includes.h"
10e28a4053SRui Paulo 
11e28a4053SRui Paulo #include "common.h"
12e28a4053SRui Paulo #include "sha1.h"
13e28a4053SRui Paulo #include "md5.h"
14e28a4053SRui Paulo 
15e28a4053SRui Paulo 
16e28a4053SRui Paulo /**
17f05cddf9SRui Paulo  * tls_prf_sha1_md5 - Pseudo-Random Function for TLS (TLS-PRF, RFC 2246)
18e28a4053SRui Paulo  * @secret: Key for PRF
19e28a4053SRui Paulo  * @secret_len: Length of the key in bytes
20e28a4053SRui Paulo  * @label: A unique label for each purpose of the PRF
21e28a4053SRui Paulo  * @seed: Seed value to bind into the key
22e28a4053SRui Paulo  * @seed_len: Length of the seed
23e28a4053SRui Paulo  * @out: Buffer for the generated pseudo-random key
24e28a4053SRui Paulo  * @outlen: Number of bytes of key to generate
25e28a4053SRui Paulo  * Returns: 0 on success, -1 on failure.
26e28a4053SRui Paulo  *
27e28a4053SRui Paulo  * This function is used to derive new, cryptographically separate keys from a
28e28a4053SRui Paulo  * given key in TLS. This PRF is defined in RFC 2246, Chapter 5.
29e28a4053SRui Paulo  */
tls_prf_sha1_md5(const u8 * secret,size_t secret_len,const char * label,const u8 * seed,size_t seed_len,u8 * out,size_t outlen)30f05cddf9SRui Paulo int tls_prf_sha1_md5(const u8 *secret, size_t secret_len, const char *label,
31e28a4053SRui Paulo 		     const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
32e28a4053SRui Paulo {
33e28a4053SRui Paulo 	size_t L_S1, L_S2, i;
34e28a4053SRui Paulo 	const u8 *S1, *S2;
35e28a4053SRui Paulo 	u8 A_MD5[MD5_MAC_LEN], A_SHA1[SHA1_MAC_LEN];
36e28a4053SRui Paulo 	u8 P_MD5[MD5_MAC_LEN], P_SHA1[SHA1_MAC_LEN];
37e28a4053SRui Paulo 	int MD5_pos, SHA1_pos;
38e28a4053SRui Paulo 	const u8 *MD5_addr[3];
39e28a4053SRui Paulo 	size_t MD5_len[3];
40e28a4053SRui Paulo 	const unsigned char *SHA1_addr[3];
41e28a4053SRui Paulo 	size_t SHA1_len[3];
42e28a4053SRui Paulo 
43e28a4053SRui Paulo 	MD5_addr[0] = A_MD5;
44e28a4053SRui Paulo 	MD5_len[0] = MD5_MAC_LEN;
45e28a4053SRui Paulo 	MD5_addr[1] = (unsigned char *) label;
46e28a4053SRui Paulo 	MD5_len[1] = os_strlen(label);
47e28a4053SRui Paulo 	MD5_addr[2] = seed;
48e28a4053SRui Paulo 	MD5_len[2] = seed_len;
49e28a4053SRui Paulo 
50e28a4053SRui Paulo 	SHA1_addr[0] = A_SHA1;
51e28a4053SRui Paulo 	SHA1_len[0] = SHA1_MAC_LEN;
52e28a4053SRui Paulo 	SHA1_addr[1] = (unsigned char *) label;
53e28a4053SRui Paulo 	SHA1_len[1] = os_strlen(label);
54e28a4053SRui Paulo 	SHA1_addr[2] = seed;
55e28a4053SRui Paulo 	SHA1_len[2] = seed_len;
56e28a4053SRui Paulo 
57e28a4053SRui Paulo 	/* RFC 2246, Chapter 5
58e28a4053SRui Paulo 	 * A(0) = seed, A(i) = HMAC(secret, A(i-1))
59e28a4053SRui Paulo 	 * P_hash = HMAC(secret, A(1) + seed) + HMAC(secret, A(2) + seed) + ..
60e28a4053SRui Paulo 	 * PRF = P_MD5(S1, label + seed) XOR P_SHA-1(S2, label + seed)
61e28a4053SRui Paulo 	 */
62e28a4053SRui Paulo 
63e28a4053SRui Paulo 	L_S1 = L_S2 = (secret_len + 1) / 2;
64e28a4053SRui Paulo 	S1 = secret;
65e28a4053SRui Paulo 	S2 = secret + L_S1;
66e28a4053SRui Paulo 	if (secret_len & 1) {
67e28a4053SRui Paulo 		/* The last byte of S1 will be shared with S2 */
68e28a4053SRui Paulo 		S2--;
69e28a4053SRui Paulo 	}
70e28a4053SRui Paulo 
71f05cddf9SRui Paulo 	hmac_md5_vector(S1, L_S1, 2, &MD5_addr[1], &MD5_len[1], A_MD5);
72e28a4053SRui Paulo 	hmac_sha1_vector(S2, L_S2, 2, &SHA1_addr[1], &SHA1_len[1], A_SHA1);
73e28a4053SRui Paulo 
74e28a4053SRui Paulo 	MD5_pos = MD5_MAC_LEN;
75e28a4053SRui Paulo 	SHA1_pos = SHA1_MAC_LEN;
76e28a4053SRui Paulo 	for (i = 0; i < outlen; i++) {
77e28a4053SRui Paulo 		if (MD5_pos == MD5_MAC_LEN) {
78f05cddf9SRui Paulo 			hmac_md5_vector(S1, L_S1, 3, MD5_addr, MD5_len, P_MD5);
79e28a4053SRui Paulo 			MD5_pos = 0;
80f05cddf9SRui Paulo 			hmac_md5(S1, L_S1, A_MD5, MD5_MAC_LEN, A_MD5);
81e28a4053SRui Paulo 		}
82e28a4053SRui Paulo 		if (SHA1_pos == SHA1_MAC_LEN) {
83e28a4053SRui Paulo 			hmac_sha1_vector(S2, L_S2, 3, SHA1_addr, SHA1_len,
84e28a4053SRui Paulo 					 P_SHA1);
85e28a4053SRui Paulo 			SHA1_pos = 0;
86e28a4053SRui Paulo 			hmac_sha1(S2, L_S2, A_SHA1, SHA1_MAC_LEN, A_SHA1);
87e28a4053SRui Paulo 		}
88e28a4053SRui Paulo 
89e28a4053SRui Paulo 		out[i] = P_MD5[MD5_pos] ^ P_SHA1[SHA1_pos];
90e28a4053SRui Paulo 
91e28a4053SRui Paulo 		MD5_pos++;
92e28a4053SRui Paulo 		SHA1_pos++;
93e28a4053SRui Paulo 	}
94e28a4053SRui Paulo 
95*206b73d0SCy Schubert 	forced_memzero(A_MD5, MD5_MAC_LEN);
96*206b73d0SCy Schubert 	forced_memzero(P_MD5, MD5_MAC_LEN);
97*206b73d0SCy Schubert 	forced_memzero(A_SHA1, SHA1_MAC_LEN);
98*206b73d0SCy Schubert 	forced_memzero(P_SHA1, SHA1_MAC_LEN);
99325151a3SRui Paulo 
100e28a4053SRui Paulo 	return 0;
101e28a4053SRui Paulo }
102