Hi,
I am trying to implement the pseudo-random function as per the rfc2104
and rfc2246.
But I am getting incorrect output.
I tried debugging and comparing it with the working function output and
I found even the output for MD5_Update() is varying.
Could someone please take a look at source code attached and point out
any obvious mistake, if present?
P.S. Please ignore any missing error handling in code, I am still trying
to get code working. And still trying to debug it.
--
Thanks,
Nilesh
#include <stdio.h>
#include <stdlib.h>
#include <openssl/rsa.h>
#include <openssl/aes.h>
#include <openssl/md5.h>
#include <openssl/sha.h>
#include <openssl/err.h>
#include <math.h>
#include <string.h>
#define KEY_LEN 128
// Dummy data:
unsigned char premaster_secret[] = "\x03\x01\x12\x20\x92\xe4\xbc\xc9\x8f\x6a\x8c\x6d\xb9\x32\x12\x8a\xe0\xcd\xea\xaa\x5f\x1c\x7c\x98\x08\x8f\x7b\x2b\x01\xcf\x26\xcd\x6f\xdd\xdb\xfe\x53\xa1\x7f\x6c\xf8\x90\x64\xbc\x66\xf2\xf1\x49";
unsigned char client_random[] = "\x4e\xfa\xe6\x78\x52\x60\xa2\x7d\xc0\x73\xfc\x81\x22\x6d\x65\xed\x7b\x3c\x8c\xf1\x46\x1e\x2f\x79\x76\xa6\x09\x37\x55\x34\xb2\xb7";
unsigned char server_random[] = "\x4e\xfa\xe6\x78\x61\x70\x97\x75\xea\x5d\xb5\x42\xb9\x10\x56\x49\xde\xe0\x1d\x7e\x27\xfd\x61\x8f\xf0\x45\x83\x28\x68\x06\x2e\x97";
unsigned char master_secret[48];
unsigned char prf_seed[64];
/* Formulae as per rfc2104 and rfc2246:
* -------------------------------------
* master_secret = PRF(premaster_secret, "master secret", client_random + server_random);
* key_block = PRF(master_secret, "key expansion", server_random + client_random);
*
* PRF(secret, lable, seed) = P_MD5(s1, label + seed) XOR P_SHA1(s2, label + seed);
* Here, s1 = first half of secret and s2 = second half of secret.
*
* P_MD5(secret, seed) = hmac_md5(secret, A(1) + seed) +
* hmac_md5(secret, A(2) + seed) + ...;
* Here, A(0) == seed, A(i) = hmac_md5(secret, A(i - 1));
*
* hmac_md5(key, text) = md5(key XOR opad, md5(key XOR ipad, text));
* Here, ipad = 0x36 byte repeated 64times and opad = 0x5C byte repeated 64times.
*/
void hmac_md5(unsigned char *key, int key_len, unsigned char *text,
int text_len, unsigned char *outbuf)
{
unsigned char k_ipad[KEY_LEN / 2 + 1];
unsigned char k_opad[KEY_LEN / 2 + 1];
MD5_CTX context;
int i = 0;
memset(&k_ipad[0], 0, sizeof(k_ipad));
memset(&k_opad[0], 0, sizeof(k_opad));
memcpy(&k_ipad[0], key, key_len);
memcpy(&k_opad[0], key, key_len);
// key xor ipad and key xor opad.
for (i = 0; i < key_len; i++) {
k_ipad[i] ^= 0x36;
k_opad[i] ^= 0x5C;
}
// md5(key XOR ipad, text);
MD5_Init(&context);
MD5_Update(&context, k_ipad, 64);
MD5_Update(&context, text, text_len);
MD5_Final(outbuf, &context);
// md5(key XOR opad, md5(key XOR ipad, text));
MD5_Init(&context);
MD5_Update(&context, k_opad, 64);
MD5_Update(&context, outbuf, 16);
MD5_Final(outbuf, &context);
}
void hmac_sha(unsigned char *key, int key_len, unsigned char *text,
int text_len, unsigned char *outbuf)
{
unsigned char k_ipad[KEY_LEN / 2 + 1];
unsigned char k_opad[KEY_LEN / 2 + 1];
SHA_CTX context;
int i = 0;
memset(&k_ipad, 0, sizeof(k_ipad));
memset(&k_opad, 0, sizeof(k_opad));
memcpy(&k_ipad[0], key, key_len);
memcpy(&k_opad[0], key, key_len);
// key xor ipad and key xor opad.
for (i = 0; i < key_len; i++) {
k_ipad[i] ^= 0x36;
k_opad[i] ^= 0x5C;
}
// md5(key XOR ipad, text);
SHA1_Init(&context);
SHA1_Update(&context, k_ipad, 64);
SHA1_Update(&context, text, text_len);
SHA1_Final(outbuf, &context);
// md5(key XOR opad, md5(key XOR ipad, text));
SHA1_Init(&context);
SHA1_Update(&context, k_opad, 64);
SHA1_Update(&context, outbuf, 20);
SHA1_Final(outbuf, &context);
}
void p_md5(unsigned char *secret, int sec_len, unsigned char *seed, int seed_len,
int count, unsigned char *outbuf)
{
int i = 0;
unsigned char start[128];
unsigned char temp[16];
unsigned char *A = (unsigned char *) malloc(16 + seed_len);
unsigned char *iterate = (unsigned char *) malloc(16 + seed_len);
unsigned char *out = &outbuf[0];
if (!A || !iterate) {
free(A);
free(iterate);
return;
}
memset(&start[0], 0, sizeof(start));
memset(&temp[0], 0, sizeof(temp));
memcpy(&start[0], seed, seed_len); // A(0) = seed.
hmac_md5(secret, sec_len, &start[0], seed_len, &temp[0]);
memcpy(A, &temp[0], 16); // A(1)
memset(&temp[0], 0, sizeof(temp));
// A(i) = HMAC_hash(secret, A(i - 1));
for (i = 0; i < count; i++) {
memcpy(iterate, A, 16);
memcpy(iterate + seed_len, &seed[0], seed_len);
hmac_md5(secret, sec_len, iterate, 16 + seed_len, &temp[0]);
memcpy(out, &temp[0], sizeof(temp));
out += sizeof(temp);
memset(&temp[0], 0, sizeof(temp));
// set A(2), A(3), ...
hmac_md5(secret, sec_len, A, 16, &temp[0]);
memcpy(A, &temp[0], sizeof(temp));
// memcpy(A + 16, &seed[0], seed_len);
memset(&temp[0], 0, sizeof(temp));
}
print_master("Out", outbuf, sizeof(temp) * 3);
}
void p_sha1(unsigned char *secret, int sec_len, unsigned char *seed, int seed_len,
int count, unsigned char *outbuf)
{
int i = 0;
unsigned char start[128];
unsigned char temp[20];
unsigned char *A = (unsigned char *) malloc(20 + seed_len);
unsigned char *out = &outbuf[0];
if (!A)
return;
memset(&start[0], 0, sizeof(start));
memset(&temp[0], 0, sizeof(temp));
memcpy(&start[0], seed, seed_len); // A(0) = seed.
hmac_sha(secret, sec_len, &start[0], seed_len, &temp[0]);
memcpy(A, &temp[0], 20);
// memcpy(A + 20, &seed[0], seed_len);
memset(&temp[0], 0, sizeof(temp));
// A(i) = HMAC_hash(secret, A(i - 1));
for (i = 0; i < count; i++) {
hmac_sha(secret, sec_len, A, 20 + seed_len, &temp[0]);
memcpy(out, &temp[0], sizeof(temp));
out += sizeof(temp);
memset(&temp[0], 0, sizeof(temp));
hmac_sha(secret, sec_len, A, 20, &temp[0]);
memcpy(A, &temp[0], sizeof(temp));
memset(&temp[0], 0, sizeof(temp));
}
}
void prf_tls10(unsigned char *secret, int sec_len, unsigned char *label,
int label_len, unsigned char *seed, int seed_len,
unsigned char *outbuf, int key_len)
{
unsigned char md5_op[160];
unsigned char sha1_op[160];
unsigned char *joined;
unsigned char *s1, *s2;
int i = 0;
int half = 0;
int s_len = seed_len, l_len = label_len;
joined = (unsigned char *) malloc(label_len + seed_len);
memset(&md5_op[0], 0, 160);
memset(&sha1_op[0], 0, 160);
if (!joined)
return;
memcpy(joined, label, label_len);
memcpy(joined+label_len, seed, seed_len);
half = (sec_len / 2) + (sec_len % 2);
s1 = (unsigned char *) malloc(sizeof(unsigned char ) * half);
s2 = (unsigned char *) malloc(sizeof(unsigned char ) * half);
if (!s1 || !s2) {
free(s1);
free(s2);
return;
}
memcpy(s1, secret, half);
memcpy(s2, secret + half, half);
p_md5(s1, half, joined, (l_len + s_len),
(int)(ceil((float)(key_len/16))), &md5_op[0]);
p_sha1(s2, half, joined, (l_len + s_len),
(int)(ceil((float)(key_len/20))), &sha1_op[0]);
for (i = 0; i < key_len; i++) {
outbuf[i] = (md5_op[i] ^ sha1_op[i]);
}
free(joined);
free(s1);
free(s2);
}
int main(void)
{
memcpy(&prf_seed[0], &client_random[0], 32);
memcpy(&prf_seed[32], &server_random[0], 32);
prf_tls10(&premaster_secret[0], 48, (unsigned char *)"master secret", 13,
&prf_seed[0], 64, &master_secret[0], 48);
printf("\n");
return 0;
}