1214501Srpaulo/*
2214501Srpaulo * TLS PRF (SHA1 + MD5)
3214501Srpaulo * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
4214501Srpaulo *
5252726Srpaulo * This software may be distributed under the terms of the BSD license.
6252726Srpaulo * See README for more details.
7214501Srpaulo */
8214501Srpaulo
9214501Srpaulo#include "includes.h"
10214501Srpaulo
11214501Srpaulo#include "common.h"
12214501Srpaulo#include "sha1.h"
13214501Srpaulo#include "md5.h"
14214501Srpaulo
15214501Srpaulo
16214501Srpaulo/**
17252726Srpaulo * tls_prf_sha1_md5 - Pseudo-Random Function for TLS (TLS-PRF, RFC 2246)
18214501Srpaulo * @secret: Key for PRF
19214501Srpaulo * @secret_len: Length of the key in bytes
20214501Srpaulo * @label: A unique label for each purpose of the PRF
21214501Srpaulo * @seed: Seed value to bind into the key
22214501Srpaulo * @seed_len: Length of the seed
23214501Srpaulo * @out: Buffer for the generated pseudo-random key
24214501Srpaulo * @outlen: Number of bytes of key to generate
25214501Srpaulo * Returns: 0 on success, -1 on failure.
26214501Srpaulo *
27214501Srpaulo * This function is used to derive new, cryptographically separate keys from a
28214501Srpaulo * given key in TLS. This PRF is defined in RFC 2246, Chapter 5.
29214501Srpaulo */
30252726Srpauloint tls_prf_sha1_md5(const u8 *secret, size_t secret_len, const char *label,
31252726Srpaulo		     const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
32214501Srpaulo{
33214501Srpaulo	size_t L_S1, L_S2, i;
34214501Srpaulo	const u8 *S1, *S2;
35214501Srpaulo	u8 A_MD5[MD5_MAC_LEN], A_SHA1[SHA1_MAC_LEN];
36214501Srpaulo	u8 P_MD5[MD5_MAC_LEN], P_SHA1[SHA1_MAC_LEN];
37214501Srpaulo	int MD5_pos, SHA1_pos;
38214501Srpaulo	const u8 *MD5_addr[3];
39214501Srpaulo	size_t MD5_len[3];
40214501Srpaulo	const unsigned char *SHA1_addr[3];
41214501Srpaulo	size_t SHA1_len[3];
42214501Srpaulo
43214501Srpaulo	if (secret_len & 1)
44214501Srpaulo		return -1;
45214501Srpaulo
46214501Srpaulo	MD5_addr[0] = A_MD5;
47214501Srpaulo	MD5_len[0] = MD5_MAC_LEN;
48214501Srpaulo	MD5_addr[1] = (unsigned char *) label;
49214501Srpaulo	MD5_len[1] = os_strlen(label);
50214501Srpaulo	MD5_addr[2] = seed;
51214501Srpaulo	MD5_len[2] = seed_len;
52214501Srpaulo
53214501Srpaulo	SHA1_addr[0] = A_SHA1;
54214501Srpaulo	SHA1_len[0] = SHA1_MAC_LEN;
55214501Srpaulo	SHA1_addr[1] = (unsigned char *) label;
56214501Srpaulo	SHA1_len[1] = os_strlen(label);
57214501Srpaulo	SHA1_addr[2] = seed;
58214501Srpaulo	SHA1_len[2] = seed_len;
59214501Srpaulo
60214501Srpaulo	/* RFC 2246, Chapter 5
61214501Srpaulo	 * A(0) = seed, A(i) = HMAC(secret, A(i-1))
62214501Srpaulo	 * P_hash = HMAC(secret, A(1) + seed) + HMAC(secret, A(2) + seed) + ..
63214501Srpaulo	 * PRF = P_MD5(S1, label + seed) XOR P_SHA-1(S2, label + seed)
64214501Srpaulo	 */
65214501Srpaulo
66214501Srpaulo	L_S1 = L_S2 = (secret_len + 1) / 2;
67214501Srpaulo	S1 = secret;
68214501Srpaulo	S2 = secret + L_S1;
69214501Srpaulo	if (secret_len & 1) {
70214501Srpaulo		/* The last byte of S1 will be shared with S2 */
71214501Srpaulo		S2--;
72214501Srpaulo	}
73214501Srpaulo
74252726Srpaulo	hmac_md5_vector(S1, L_S1, 2, &MD5_addr[1], &MD5_len[1], A_MD5);
75214501Srpaulo	hmac_sha1_vector(S2, L_S2, 2, &SHA1_addr[1], &SHA1_len[1], A_SHA1);
76214501Srpaulo
77214501Srpaulo	MD5_pos = MD5_MAC_LEN;
78214501Srpaulo	SHA1_pos = SHA1_MAC_LEN;
79214501Srpaulo	for (i = 0; i < outlen; i++) {
80214501Srpaulo		if (MD5_pos == MD5_MAC_LEN) {
81252726Srpaulo			hmac_md5_vector(S1, L_S1, 3, MD5_addr, MD5_len, P_MD5);
82214501Srpaulo			MD5_pos = 0;
83252726Srpaulo			hmac_md5(S1, L_S1, A_MD5, MD5_MAC_LEN, A_MD5);
84214501Srpaulo		}
85214501Srpaulo		if (SHA1_pos == SHA1_MAC_LEN) {
86214501Srpaulo			hmac_sha1_vector(S2, L_S2, 3, SHA1_addr, SHA1_len,
87214501Srpaulo					 P_SHA1);
88214501Srpaulo			SHA1_pos = 0;
89214501Srpaulo			hmac_sha1(S2, L_S2, A_SHA1, SHA1_MAC_LEN, A_SHA1);
90214501Srpaulo		}
91214501Srpaulo
92214501Srpaulo		out[i] = P_MD5[MD5_pos] ^ P_SHA1[SHA1_pos];
93214501Srpaulo
94214501Srpaulo		MD5_pos++;
95214501Srpaulo		SHA1_pos++;
96214501Srpaulo	}
97214501Srpaulo
98214501Srpaulo	return 0;
99214501Srpaulo}
100