www.pudn.com > truecrypt.zip > PKCS5.C


/* Copyright (C) 2004 TrueCrypt Team, truecrypt.org 
   This product uses components written by Paul Le Roux  */ 
 
#include "TCdefs.h" 
 
#include  
#include "sha1.h" 
#include "md5.h" 
#include "pkcs5.h" 
 
void truncate 
  ( 
	  char *d1,		/* data to be truncated */ 
	  char *d2,		/* truncated data */ 
	  int len		/* length in bytes to keep */ 
) 
{ 
	int i; 
	for (i = 0; i < len; i++) 
		d2[i] = d1[i]; 
} 
 
 
/* Function to compute the digest */ 
void 
  hmac_sha 
  ( 
	  char *k,		/* secret key */ 
	  int lk,		/* length of the key in bytes */ 
	  char *d,		/* data */ 
	  int ld,		/* length of data in bytes */ 
	  char *out,		/* output buffer, at least "t" bytes */ 
	  int t 
) 
{ 
	SHA1_CTX ictx, octx; 
	char isha[SHA_DIGESTSIZE], osha[SHA_DIGESTSIZE]; 
	char key[SHA_DIGESTSIZE]; 
	char buf[SHA_BLOCKSIZE]; 
	int i; 
 
	if (lk > SHA_BLOCKSIZE) 
	{ 
 
		SHA1_CTX tctx; 
 
		SHA1Init (&tctx); 
		SHA1Update (&tctx, (unsigned char *) k, lk); 
		SHA1Final ((unsigned char *) key, &tctx); 
 
		k = key; 
		lk = SHA_DIGESTSIZE; 
	} 
 
	/**** Inner Digest ****/ 
 
	SHA1Init (&ictx); 
 
	/* Pad the key for inner digest */ 
	for (i = 0; i < lk; ++i) 
		buf[i] = (char) (k[i] ^ 0x36); 
	for (i = lk; i < SHA_BLOCKSIZE; ++i) 
		buf[i] = 0x36; 
 
	SHA1Update (&ictx, (unsigned char *) buf, SHA_BLOCKSIZE); 
	SHA1Update (&ictx, (unsigned char *) d, ld); 
 
	SHA1Final ((unsigned char *) isha, &ictx); 
 
	/**** Outter Digest ****/ 
 
	SHA1Init (&octx); 
 
	for (i = 0; i < lk; ++i) 
		buf[i] = (char) (k[i] ^ 0x5C); 
	for (i = lk; i < SHA_BLOCKSIZE; ++i) 
		buf[i] = 0x5C; 
 
	SHA1Update (&octx, (unsigned char *) buf, SHA_BLOCKSIZE); 
	SHA1Update (&octx, (unsigned char *) isha, SHA_DIGESTSIZE); 
 
	SHA1Final ((unsigned char *) osha, &octx); 
 
	/* truncate and print the results */ 
	t = t > SHA_DIGESTSIZE ? SHA_DIGESTSIZE : t; 
	truncate (osha, out, t); 
} 
 
 
void 
derive_u_sha (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *u, int b) 
{ 
	char j[SHA_DIGESTSIZE], k[SHA_DIGESTSIZE]; 
	char init[128]; 
	char counter[4]; 
	int c, i; 
 
	/* iteration 1 */ 
	memset (counter, 0, 4); 
	counter[3] = (char) b; 
	memcpy (init, salt, salt_len);	/* salt */ 
	memcpy (&init[salt_len], counter, 4);	/* big-endian block number */ 
	hmac_sha (pwd, pwd_len, init, salt_len + 4, j, SHA_DIGESTSIZE); 
	memcpy (u, j, SHA_DIGESTSIZE); 
 
	/* remaining iterations */ 
	for (c = 1; c < iterations; c++) 
	{ 
		hmac_sha (pwd, pwd_len, j, SHA_DIGESTSIZE, k, SHA_DIGESTSIZE); 
		for (i = 0; i < SHA_DIGESTSIZE; i++) 
		{ 
			u[i] ^= k[i]; 
			j[i] = k[i]; 
		} 
	} 
} 
 
void 
derive_sha_key (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *dk, int dklen) 
{ 
	char u[SHA_DIGESTSIZE]; 
	int b, l, r; 
 
	if (dklen % SHA_DIGESTSIZE) 
	{ 
		l = 1 + dklen / SHA_DIGESTSIZE; 
	} 
	else 
	{ 
		l = dklen / SHA_DIGESTSIZE; 
	} 
 
	r = dklen - (l - 1) * SHA_DIGESTSIZE; 
 
	/* first l - 1 blocks */ 
	for (b = 1; b < l; b++) 
	{ 
		derive_u_sha (pwd, pwd_len, salt, salt_len, iterations, u, b); 
		memcpy (dk, u, SHA_DIGESTSIZE); 
		dk += SHA_DIGESTSIZE; 
	} 
 
	/* last block */ 
	derive_u_sha (pwd, pwd_len, salt, salt_len, iterations, u, b); 
	memcpy (dk, u, r); 
} 
 
#define MD5_DIGESTSIZE 16 
 
void 
hmac_md5 (char *text,		/* pointer to data stream */ 
	  int text_len,		/* length of data stream */ 
	  char *key,		/* pointer to authentication key */ 
	  int key_len,		/* length of authentication key */ 
	  char *digest)		/* caller digest to be filled in */ 
{ 
	MD5_CTX context; 
	char k_ipad[65];	/* inner padding - key XORd with ipad */ 
	char k_opad[65];	/* outer padding - key XORd with opad */ 
	char tk[MD5_DIGESTSIZE]; 
	int i; 
	/* if key is longer than 64 bytes reset it to key=MD5(key) */ 
	if (key_len > 64) 
	{ 
 
		MD5_CTX tctx; 
 
		MD5Init (&tctx); 
		MD5Update (&tctx, (unsigned char *) key, key_len); 
		MD5Final ((unsigned char *) tk, &tctx); 
 
		key = tk; 
		key_len = MD5_DIGESTSIZE; 
	} 
 
	/* the HMAC_MD5 transform looks like: 
	 
	MD5(K XOR opad, MD5(K XOR ipad, text)) 
	 
	where K is an n byte key ipad is the byte 0x36 repeated 64 times opad 
	   is the byte 0x5c repeated 64 times and text is the data being 
	   protected */ 
 
	/* start out by storing key in pads */ 
	memset (k_ipad, 0, sizeof k_ipad); 
	memset (k_opad, 0, sizeof k_opad); 
	memcpy (k_ipad, key, key_len); 
	memcpy (k_opad, key, key_len); 
 
	/* XOR key with ipad and opad values */ 
	for (i = 0; i < 64; i++) 
	{ 
		k_ipad[i] ^= 0x36; 
		k_opad[i] ^= 0x5c; 
	} 
 
	/* perform inner MD5 */ 
	MD5Init (&context);	/* init context for 1st pass */ 
	MD5Update (&context, (unsigned char *) k_ipad, 64);	/* start with inner pad */ 
	MD5Update (&context, (unsigned char *) text, text_len);	/* then text of datagram */ 
	MD5Final ((unsigned char *) digest, &context);	/* finish up 1st pass */ 
	/* perform outer MD5 */ 
	MD5Init (&context);	/* init context for 2nd pass */ 
	MD5Update (&context, (unsigned char *) k_opad, 64);	/* start with outer pad */ 
	MD5Update (&context, (unsigned char *) digest, MD5_DIGESTSIZE);	/* then results of 1st 
									   hash */ 
	MD5Final ((unsigned char *) digest, &context);	/* finish up 2nd pass */ 
} 
 
void 
derive_u_md5 (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *u, int b) 
{ 
	char j[MD5_DIGESTSIZE], k[MD5_DIGESTSIZE]; 
	char init[128]; 
	char counter[4]; 
	int c, i; 
 
	/* iteration 1 */ 
	memset (counter, 0, 4); 
	counter[3] = (char) b; 
	memcpy (init, salt, salt_len);	/* salt */ 
	memcpy (&init[salt_len], counter, 4);	/* big-endian block number */ 
	hmac_md5 (pwd, pwd_len, init, salt_len + 4, j); 
	memcpy (u, j, MD5_DIGESTSIZE); 
 
	/* remaining iterations */ 
	for (c = 1; c < iterations; c++) 
	{ 
		hmac_md5 (pwd, pwd_len, j, MD5_DIGESTSIZE, k); 
		for (i = 0; i < MD5_DIGESTSIZE; i++) 
		{ 
			u[i] ^= k[i]; 
			j[i] = k[i]; 
		} 
	} 
} 
 
void 
derive_md5_key (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *dk, int dklen) 
{ 
	char u[MD5_DIGESTSIZE]; 
	int b, l, r; 
 
	if (dklen % MD5_DIGESTSIZE) 
	{ 
		l = 1 + dklen / MD5_DIGESTSIZE; 
	} 
	else 
	{ 
		l = dklen / MD5_DIGESTSIZE; 
	} 
 
	r = dklen - (l - 1) * MD5_DIGESTSIZE; 
 
	/* first l - 1 blocks */ 
	for (b = 1; b < l; b++) 
	{ 
		derive_u_md5 (pwd, pwd_len, salt, salt_len, iterations, u, b); 
		memcpy (dk, u, MD5_DIGESTSIZE); 
		dk += MD5_DIGESTSIZE; 
	} 
 
	/* last block */ 
	derive_u_md5 (pwd, pwd_len, salt, salt_len, iterations, u, b); 
	memcpy (dk, u, r); 
} 
 
 
 
/* rfc2104 & 2202 */ 
 
char *hmac_test_keys[3] = 
{ 
	"\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", 
	"Jefe", 
	"\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" 
}; 
 
 
char *hmac_test_data[3] = 
{ 
	"Hi There", 
	"what do ya want for nothing?", 
	"\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" 
      "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" 
	"\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" 
}; 
 
char *hmac_md5_test_vectors[3] = 
{ 
	"\x92\x94\x72\x7a\x36\x38\xbb\x1c\x13\xf4\x8e\xf8\x15\x8b\xfc\x9d", 
	"\x75\x0c\x78\x3e\x6a\xb0\xb5\x03\xea\xa8\x6e\x31\x0a\x5d\xb7\x38", 
	"\x56\xbe\x34\x52\x1d\x14\x4c\x88\xdb\xb8\xc7\x33\xf0\xe8\xb3\xf6" 
}; 
 
char *hmac_sha_test_vectors[3] = 
{ 
	"\xb6\x17\x31\x86\x55\x05\x72\x64\xe2\x8b\xc0\xb6\xfb\x37\x8c\x8e\xf1\x46\xbe\x00", 
	"\xef\xfc\xdf\x6a\xe5\xeb\x2f\xa2\xd2\x74\x16\xd5\xf1\x84\xdf\x9c\x25\x9a\x7c\x79", 
	"\x12\x5d\x73\x42\xb9\xac\x11\xcd\x91\xa3\x9a\xf4\x8a\xa1\x7b\x4f\x63\xf1\x75\xd3" 
}; 
 
BOOL 
test_hmac_sha1 () 
{ 
	BOOL bOK = TRUE; 
	int i; 
 
	for (i = 0; i < 3; i++) 
	{ 
		char digest[SHA_DIGESTSIZE]; 
		hmac_sha (hmac_test_keys[i], strlen (hmac_test_keys[i]), hmac_test_data[i], strlen (hmac_test_data[i]), digest, SHA_DIGESTSIZE); 
		if (memcmp (digest, hmac_sha_test_vectors[i], SHA_DIGESTSIZE) != 0) 
			return FALSE; 
	} 
 
	return TRUE; 
} 
 
BOOL 
test_hmac_md5 () 
{ 
	int i; 
	for (i = 0; i < 3; i++) 
	{ 
		char digest[MD5_DIGESTSIZE]; 
		int x = strlen (hmac_test_keys[i]); 
		hmac_md5 (hmac_test_data[i], strlen (hmac_test_data[i]), hmac_test_keys[i], x > MD5_DIGESTSIZE ? MD5_DIGESTSIZE : x, digest); 
		if (memcmp (digest, hmac_md5_test_vectors[i], MD5_DIGESTSIZE) != 0) 
			return FALSE; 
	} 
 
	return TRUE; 
} 
 
BOOL 
test_pkcs5 () 
{ 
	char dk[4]; 
 
	/* First make sure the hmacs are ok */ 
	if (test_hmac_sha1 ()== FALSE) 
		return FALSE; 
	if (test_hmac_md5 ()== FALSE) 
		return FALSE; 
 
	/* Next check the sha1 with pkcs5 */ 
	derive_sha_key ("password", 8, "\x12\x34\x56\x78", 4, 5, dk, 4); 
	if (memcmp (dk, "\x5c\x75\xce\xf0", 4) != 0) 
		return FALSE; 
 
	/* Next check md5 with pkcs5 */ 
	derive_md5_key ("password", 8, "\x12\x34\x56\x78", 4, 5, dk, 4); 
	if (memcmp (dk, "\x91\xa9\xd7\x92", 4) != 0) 
		return FALSE; 
 
	return TRUE; 
 
}