sha1-tlsprf.c revision 8d520ff1dc2da35cdca849e982051b86468016d8
124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner/*
224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner * TLS PRF (SHA1 + MD5)
324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner *
524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner * This program is free software; you can redistribute it and/or modify
624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner * it under the terms of the GNU General Public License version 2 as
724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner * published by the Free Software Foundation.
824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner *
924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner * Alternatively, this software may be distributed under the terms of BSD
1024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner * license.
1123b8abbe214c252028f6e09f79169529c846409dGreg Clayton *
1269aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton * See README and COPYING for more details.
137dd5c51fbab8384b18f20ecc125f9a1bb3c9bcb2Greg Clayton */
1498f930f429160f9777f626c3ac6aa609f4e965d2Caroline Tice
157dd5c51fbab8384b18f20ecc125f9a1bb3c9bcb2Greg Clayton#include "includes.h"
1623b8abbe214c252028f6e09f79169529c846409dGreg Clayton
177dd5c51fbab8384b18f20ecc125f9a1bb3c9bcb2Greg Clayton#include "common.h"
187dd5c51fbab8384b18f20ecc125f9a1bb3c9bcb2Greg Clayton#include "sha1.h"
1924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner#include "md5.h"
2069aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton#include "crypto.h"
2198f930f429160f9777f626c3ac6aa609f4e965d2Caroline Tice
227dd5c51fbab8384b18f20ecc125f9a1bb3c9bcb2Greg Clayton
237dd5c51fbab8384b18f20ecc125f9a1bb3c9bcb2Greg Clayton/**
247dd5c51fbab8384b18f20ecc125f9a1bb3c9bcb2Greg Clayton * tls_prf - Pseudo-Random Function for TLS (TLS-PRF, RFC 2246)
2524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner * @secret: Key for PRF
2624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner * @secret_len: Length of the key in bytes
2769aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton * @label: A unique label for each purpose of the PRF
2824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner * @seed: Seed value to bind into the key
2924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner * @seed_len: Length of the seed
3024943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner * @out: Buffer for the generated pseudo-random key
3163094e0bb161580564954dee512955c1c79d3476Greg Clayton * @outlen: Number of bytes of key to generate
3224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner * Returns: 0 on success, -1 on failure.
3324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner *
3424943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner * This function is used to derive new, cryptographically separate keys from a
3524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner * given key in TLS. This PRF is defined in RFC 2246, Chapter 5.
3663094e0bb161580564954dee512955c1c79d3476Greg Clayton */
3724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattnerint tls_prf(const u8 *secret, size_t secret_len, const char *label,
3824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner	    const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
3924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner{
40538eb82a89a68dbc57251915080bd5152b333978Greg Clayton	size_t L_S1, L_S2, i;
41538eb82a89a68dbc57251915080bd5152b333978Greg Clayton	const u8 *S1, *S2;
42538eb82a89a68dbc57251915080bd5152b333978Greg Clayton	u8 A_MD5[MD5_MAC_LEN], A_SHA1[SHA1_MAC_LEN];
43538eb82a89a68dbc57251915080bd5152b333978Greg Clayton	u8 P_MD5[MD5_MAC_LEN], P_SHA1[SHA1_MAC_LEN];
44538eb82a89a68dbc57251915080bd5152b333978Greg Clayton	int MD5_pos, SHA1_pos;
45538eb82a89a68dbc57251915080bd5152b333978Greg Clayton	const u8 *MD5_addr[3];
46538eb82a89a68dbc57251915080bd5152b333978Greg Clayton	size_t MD5_len[3];
47538eb82a89a68dbc57251915080bd5152b333978Greg Clayton	const unsigned char *SHA1_addr[3];
48538eb82a89a68dbc57251915080bd5152b333978Greg Clayton	size_t SHA1_len[3];
49538eb82a89a68dbc57251915080bd5152b333978Greg Clayton
50538eb82a89a68dbc57251915080bd5152b333978Greg Clayton	if (secret_len & 1)
51538eb82a89a68dbc57251915080bd5152b333978Greg Clayton		return -1;
5224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
5324943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner	MD5_addr[0] = A_MD5;
5463094e0bb161580564954dee512955c1c79d3476Greg Clayton	MD5_len[0] = MD5_MAC_LEN;
5524943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner	MD5_addr[1] = (unsigned char *) label;
5624943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner	MD5_len[1] = os_strlen(label);
5724943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner	MD5_addr[2] = seed;
5824943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner	MD5_len[2] = seed_len;
5924943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner
6063094e0bb161580564954dee512955c1c79d3476Greg Clayton	SHA1_addr[0] = A_SHA1;
6124943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner	SHA1_len[0] = SHA1_MAC_LEN;
6224943d2ee8bfaa7cf5893e4709143924157a5c1eChris Lattner	SHA1_addr[1] = (unsigned char *) label;
6369aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton	SHA1_len[1] = os_strlen(label);
6469aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton	SHA1_addr[2] = seed;
6569aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton	SHA1_len[2] = seed_len;
6669aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton
6769aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton	/* RFC 2246, Chapter 5
6869aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton	 * A(0) = seed, A(i) = HMAC(secret, A(i-1))
6969aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton	 * P_hash = HMAC(secret, A(1) + seed) + HMAC(secret, A(2) + seed) + ..
7069aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton	 * PRF = P_MD5(S1, label + seed) XOR P_SHA-1(S2, label + seed)
7169aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton	 */
7269aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton
7369aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton	L_S1 = L_S2 = (secret_len + 1) / 2;
7469aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton	S1 = secret;
7569aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton	S2 = secret + L_S1;
7669aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton	if (secret_len & 1) {
7769aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton		/* The last byte of S1 will be shared with S2 */
7869aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton		S2--;
7969aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton	}
8069aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton
8169aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton	hmac_md5_vector_non_fips_allow(S1, L_S1, 2, &MD5_addr[1], &MD5_len[1],
8269aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton				       A_MD5);
8369aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton	hmac_sha1_vector(S2, L_S2, 2, &SHA1_addr[1], &SHA1_len[1], A_SHA1);
8469aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton
8569aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton	MD5_pos = MD5_MAC_LEN;
8669aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton	SHA1_pos = SHA1_MAC_LEN;
8769aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton	for (i = 0; i < outlen; i++) {
8869aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton		if (MD5_pos == MD5_MAC_LEN) {
8969aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton			hmac_md5_vector_non_fips_allow(S1, L_S1, 3, MD5_addr,
9069aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton						       MD5_len, P_MD5);
9169aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton			MD5_pos = 0;
9269aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton			hmac_md5_non_fips_allow(S1, L_S1, A_MD5, MD5_MAC_LEN,
9369aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton						A_MD5);
9469aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton		}
9569aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton		if (SHA1_pos == SHA1_MAC_LEN) {
9669aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton			hmac_sha1_vector(S2, L_S2, 3, SHA1_addr, SHA1_len,
9769aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton					 P_SHA1);
9869aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton			SHA1_pos = 0;
9969aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton			hmac_sha1(S2, L_S2, A_SHA1, SHA1_MAC_LEN, A_SHA1);
10069aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton		}
10169aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton
10269aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton		out[i] = P_MD5[MD5_pos] ^ P_SHA1[SHA1_pos];
10369aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton
10469aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton		MD5_pos++;
10569aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton		SHA1_pos++;
10669aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton	}
10769aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton
10869aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton	return 0;
10969aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton}
11069aa5d9a7620a183cdc4da12cc87ea82e2ffcbf9Greg Clayton