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;
}

Reply via email to