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