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