$search
00001 /* 00002 * TLS PRF (SHA1 + MD5) 00003 * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi> 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License version 2 as 00007 * published by the Free Software Foundation. 00008 * 00009 * Alternatively, this software may be distributed under the terms of BSD 00010 * license. 00011 * 00012 * See README and COPYING for more details. 00013 */ 00014 00015 #include "includes.h" 00016 00017 #include "common.h" 00018 #include "sha1.h" 00019 #include "md5.h" 00020 #include "crypto.h" 00021 00022 00037 int tls_prf(const u8 *secret, size_t secret_len, const char *label, 00038 const u8 *seed, size_t seed_len, u8 *out, size_t outlen) 00039 { 00040 size_t L_S1, L_S2, i; 00041 const u8 *S1, *S2; 00042 u8 A_MD5[MD5_MAC_LEN], A_SHA1[SHA1_MAC_LEN]; 00043 u8 P_MD5[MD5_MAC_LEN], P_SHA1[SHA1_MAC_LEN]; 00044 int MD5_pos, SHA1_pos; 00045 const u8 *MD5_addr[3]; 00046 size_t MD5_len[3]; 00047 const unsigned char *SHA1_addr[3]; 00048 size_t SHA1_len[3]; 00049 00050 if (secret_len & 1) 00051 return -1; 00052 00053 MD5_addr[0] = A_MD5; 00054 MD5_len[0] = MD5_MAC_LEN; 00055 MD5_addr[1] = (unsigned char *) label; 00056 MD5_len[1] = os_strlen(label); 00057 MD5_addr[2] = seed; 00058 MD5_len[2] = seed_len; 00059 00060 SHA1_addr[0] = A_SHA1; 00061 SHA1_len[0] = SHA1_MAC_LEN; 00062 SHA1_addr[1] = (unsigned char *) label; 00063 SHA1_len[1] = os_strlen(label); 00064 SHA1_addr[2] = seed; 00065 SHA1_len[2] = seed_len; 00066 00067 /* RFC 2246, Chapter 5 00068 * A(0) = seed, A(i) = HMAC(secret, A(i-1)) 00069 * P_hash = HMAC(secret, A(1) + seed) + HMAC(secret, A(2) + seed) + .. 00070 * PRF = P_MD5(S1, label + seed) XOR P_SHA-1(S2, label + seed) 00071 */ 00072 00073 L_S1 = L_S2 = (secret_len + 1) / 2; 00074 S1 = secret; 00075 S2 = secret + L_S1; 00076 if (secret_len & 1) { 00077 /* The last byte of S1 will be shared with S2 */ 00078 S2--; 00079 } 00080 00081 hmac_md5_vector_non_fips_allow(S1, L_S1, 2, &MD5_addr[1], &MD5_len[1], 00082 A_MD5); 00083 hmac_sha1_vector(S2, L_S2, 2, &SHA1_addr[1], &SHA1_len[1], A_SHA1); 00084 00085 MD5_pos = MD5_MAC_LEN; 00086 SHA1_pos = SHA1_MAC_LEN; 00087 for (i = 0; i < outlen; i++) { 00088 if (MD5_pos == MD5_MAC_LEN) { 00089 hmac_md5_vector_non_fips_allow(S1, L_S1, 3, MD5_addr, 00090 MD5_len, P_MD5); 00091 MD5_pos = 0; 00092 hmac_md5_non_fips_allow(S1, L_S1, A_MD5, MD5_MAC_LEN, 00093 A_MD5); 00094 } 00095 if (SHA1_pos == SHA1_MAC_LEN) { 00096 hmac_sha1_vector(S2, L_S2, 3, SHA1_addr, SHA1_len, 00097 P_SHA1); 00098 SHA1_pos = 0; 00099 hmac_sha1(S2, L_S2, A_SHA1, SHA1_MAC_LEN, A_SHA1); 00100 } 00101 00102 out[i] = P_MD5[MD5_pos] ^ P_SHA1[SHA1_pos]; 00103 00104 MD5_pos++; 00105 SHA1_pos++; 00106 } 00107 00108 return 0; 00109 }