Hi,
I am a newbie in the cryptography area and learning by writing some test
code.
I have setup the apache server and capturing packets using wireshark.
I have a query specific to RC4. With the given server private key, I am
able to generate master secret and key block correctly.
My test code output matches with Wireshark debug logs (i.e. the master
secret generated and key block generated using pseudo-random function).
However, I am unable to understand how to use the RC4_set_key() and
RC4() APIs.
What exact part of key_block should I feed to RC4_set_key()?
key_block[0..15] - client MAC
key_block[16..31] - server MAC
key_block[32..48] - client Write key
key_block[49..64] - server Write key
Please see the test code attached (please pardon the code formatting).
--
Thanks,
Nilesh
#include <openssl/rsa.h>
#include <openssl/rc4.h>
#include <openssl/md5.h>
#include <openssl/sha.h>
#include <openssl/err.h>
#include <string.h>
void sec_hash_48(unsigned char * out, unsigned char * in, unsigned char * salt1,
unsigned char * salt2, unsigned char salt);
void sec_hash_64(unsigned char * out, unsigned char * in, unsigned char * salt1,
unsigned char * salt2, unsigned char salt);
void printmem(char *str, unsigned char *mem, unsigned int len, unsigned char hex);
/* Data extracted from packet. */
unsigned char client_random[] = "\x4e\x95\x38\xa1\x20\x7a\x9e\x47\x4e\xaa\x0c\xfd\xa3\x06\xf9\xa7\x0c\x09\xc7\xc5\x6e\x50\x7d\xbf\xb0\x7d\x4e\x1b\xb4\xbd\xcd\x59";
unsigned char server_random[] = "\x4e\x95\x38\xa0\x05\xf0\x06\x5f\x6d\x06\x2d\xfa\x15\x31\x5e\xa7\xe0\x0e\xc9\x26\x28\x82\x4b\xc8\x66\x87\xff\xbd\x10\x60\x2b\x18";
unsigned char iv[] = "\xe2\x95\x6b\x86\x77\x7e\xed\xfe\xe0\x3c\x09\xab\x99\xea\xcc\x69";
unsigned char to_decrypt_key[] = "\x3b\xdb\x06\x4c\x0d\xd5\x42\xc4\x2e\xb4\xbc\xb9\x2e\x45\x30\xa9\x00\xf8\x4d\xd1\x7b\x0c\x73\x80\xcd\xff\xd1\x7e\x40\x30\x99\x2b\xc0\x8c\xcb\x42\x6c\xe8\x43\x0f\x6c\x0b\xd1\xa5\xdd\x44\x3f\xaa\x2b\x33\xc7\x54\x33\x5e\x14\x1a\x29\x9d\x98\xdb\x08\x6a\x16\xeb\xfe\x7d\xef\x04\x7d\x65\x5a\xf3\xf3\x65\xf4\x75\x77\x3c\xa2\x23\xd4\xdc\x23\xf4\x11\x1f\xb4\x83\x94\x75\xf7\x81\x4f\x14\x59\x1b\xc8\x0d\x27\x9a\x3e\x1b\x03\xf3\x5f\x92\xe3\xd8\x47\x54\xc8\xf5\x68\x2f\xbb\xdf\xe3\xdd\xaa\xf9\x7f\xc9\x8d\x45\x8c\xc0\xc2\x56";
unsigned char inbuf[4096] = "\x0f\xc6\xcd\x17\xa8\x0b\xaa\xa2\x9c\xed\xe9\x7f\xba\x10\xcb\x23\xd0\x0b\x23\xba\x4b\x8b\x9b\xfc\x96\xab\x9e\x14\x46\x94\xaa\xfa\xbb\x81\xc5\x91\x17\x7c\xba\xd7\x27\x17\x31\xd1\xfe\xd2\x8b\x00\xa1\x46\x19\xe6\xdd\x94\xd0\x71\xab\x03\xcf\xe7\xbe\xb8\x37\xd9\xe0\xcb\x46\x23\x08\xe7\x7b\xc0\xae\xc2\x5d\x3e\x93\x07\xc7\x75\x31\x34\x41\x4e\x6e\x90\x42\xf7\x47\xc5\x53\x07\x2a\x98\x71\x0d\x8b\x50\x03\xd0\xa1\x7a\x12\xbe\x71\x35\x30\x19\x1e\xf1\x1a\x5e\xf4\x96\x1d\x25\x3a\x9d\x35\xb6\x79\x0e\xbd\xb7\xc8\x11\xae\x81\x86\x75\x7a\x36\x29\x22\x27\x78\x92\xe7\x8a\x52\x81\x57\x01\x62\x39\x9d\x66\xb2\xf5\xe5\x4f\x2c\x05\x4e\x71\x30\x77\xf4\x1e\xcf\x30\xe0\x78\x4a\x1c\x53\x1e\xd2\x1f\x37\x91\x4e\x6f\xe6\xc1\x68\x02\x01\x01\x4d\x24\xf0\xe9\xa2\x6e\x63\x2c\xc1\xfa\x47\xc2\x00\x01\x07\x0b\xed\xcf\x1a\x1e\x45\x5d\x71\xbd\x1d\xe5\x4b\xf3\xbb\x56\xb4\x19\x68\x09\xdc\x9c\x96\xbe\x1e\x0f\xf1\x87\x39\x9e\x5a\x1b\x42\x94\x00\x04\xc0\x6f\x94\xaf\x72\x25\xaa\xf5\xf3\x31\x2e\x24\x61\xb4\xa0\xb1\x09\xfe\x2e\xaf\x80\xa7\x11\x20\x60\x9d\x7d\x35\x4d\xf6\xb4\x2b\x21\xa7\x9f\xa8\x73\x13\x86\x5f\x95\x27\x17\x9d\x3b\xe2\xdc\x92\x98\xbc\xea\x8f\xff\xb1\xa7\x15\x9f\x5e\x66\x96\xe2\x0d\x6e\x39\x32\x59\x88\x58\xcd\x79\x37\xaa\xe0\x97\xff\x71\x78\x44\x43\x2f\x43\x4e\xd3\xb8\xde\x7c\xbc\xac\x8e\x8d\xa7\xcc\xee\x27\xe8\x05\x8c\xe1\x82\xc8\x2c\x7f\x58\x1b\xb3\x40\x5a\x7d\x68\x10\x19\x52\x39\xf7\x37\x8c\xe0\xa3\x9b\x61\x19\x04\xc8\x4d\x4e\x6b\x27\xad\xc4\x3a\xe1\x19\xb3\x94\x6d\xe2\x84\x18\x51\xcc\x1a\xea\x91\xfd\xba\x00\x1e\x2a\x7d\x95\x3f\x2b\x9b\xfe\xf9\x93\x1a\x2f\x2a\x9d\x26\xcd\x42\x1d\x95\x21\xa6\x0c\x45\xbf";
/* This matches with wireshark debug logs.
Premaster: 3 0 80 4a 1c 2b 72 4a 88 19 c1 5c 6b 55 1c 63 46 1 16 b9 94 3b 7c 6b 12 80 a a4 24 d6 b1 ac 3d 71 87 12 b9 7 1 47 a4 3c c3 8b 31 54 c3 f4
Master secret: 9f e3 1 2c 47 8b 56 bf 78 1a f7 9f a6 1c b0 40 ff f5 68 5b 67 31 90 83 a9 a0 e e4 72 64 ee 6a 1d 5a e1 19 61 a8 96 21 3e da 5e dc c9 ef 36 fc
key block: 1 ec 86 47 58 3b 4b 62 60 90 fd 43 84 aa 55 f2 85 41 fc 87 6f c7 61 38 c fd a6 48 ef 9e 14 98 e7 88 10 68 38 54 4 9a 22 1c 23 8c 87 82 bd 7a 4b b9 1a 35 26 ac 93 bb 48 96 84 9e eb d1 43 da
*/
#define DEBUG
#ifdef DEBUG
#define PRINT(str, mem, len, hex) printmem(str, mem, len, hex);
#else
#define PRINT(str, mem, len, hex) 0
#endif
int main(void)
{
// For reading the key.
RSA *rsa;
FILE *fp;
int i, check, pre_master_len = 128;
// The decrypted premaster secret.
unsigned char pre_master[48];
// The decrypted master secret.
unsigned char master_secret[48];
// Key block generated.
unsigned char key_block[144];
// The decrypted data buff.
unsigned char outbuf[4096];
unsigned int rid = 0;
unsigned char err_buf[1024];
Uint64 context_handle;
int rc;
RC4_KEY sch;
SSL3_RECORD *rec = (SSL3_RECORD *) malloc (sizeof(SSL3_RECORD));
if (!rec) {
printf("Malloc failure.\n");
return -1;
}
printf("Cavium initialization....\n");
if (CspInitialize(CAVIUM_DIRECT, CAVIUM_DEV_ID)) {
printf("Error! Cavium init failed!!\n");
return -1;
}
if (CspAllocContext(CONTEXT_SSL, &context_handle, CAVIUM_DEV_ID)) {
printf("Error! Context alloc failed!!\n");
return -1;
}
rsa = RSA_new();
/* 1 Open server's private key file */
if ((fp = fopen("server.key", "rb")) == NULL) {
printf("Cannot open server key file.\n");
return;
}
/* 2 Generate RSA struct from private key file */
PEM_read_RSAPrivateKey(fp, &rsa, NULL, NULL);
/* 3 Check for successful key generation */
if (RSA_check_key(rsa) != 1) {
printf("RSA_check_key(): PrivateKey check failed\n");
return;
}
/* 4 Using Private RSA Key, decode the client_pre_master_secret */
check = RSA_private_decrypt(pre_master_len, to_decrypt_key,
pre_master, rsa, RSA_PKCS1_PADDING);
if (check == -1) {
printf("RSA_private_decrypt() failed : %d\n", check);
printf("Decrypt failed: %s\n",
ERR_error_string(ERR_get_error(), err_buf));
exit(1);
}
PRINT("\nPremaster: ",pre_master,check,1);
/* 5 Generate master secret */
sec_hash_48(master_secret, pre_master, client_random, server_random, 'A');
PRINT("\nMaster secret: ",master_secret,48,1);
/* 6 Generate key block. For RC4 it will be 64bytes.*/
sec_hash_64(key_block, master_secret, server_random, client_random, 'A');
PRINT("\nkey block: ",key_block, 64,1);
RC4_set_key(&sch, 16, &key_block[48]);
memset(&outbuf[0], 0, sizeof(outbuf));
RC4(&sch, 399, inbuf, outbuf);
printf("\nData : %s", outbuf);
PRINT("\nHttp : \n",outbuf,4096,1);
printf("\n");
return 0;
}
/* 48-byte transformation used to generate master secret and key material. Both SHA1 and MD5 algorithms are used. */
void sec_hash_48(unsigned char * out, unsigned char * in, unsigned char * salt1, unsigned char * salt2, unsigned char salt)
{
unsigned char shasig[20];
unsigned char pad[4];
SHA_CTX sha;
MD5_CTX md5;
int i;
for (i = 0; i < 3; i++)
{
memset(pad, salt + i, i + 1);
SHA1_Init(&sha);
SHA1_Update(&sha, pad, i + 1);
SHA1_Update(&sha, in, 48);
SHA1_Update(&sha, salt1, 32);
SHA1_Update(&sha, salt2, 32);
SHA1_Final(shasig, &sha);
MD5_Init(&md5);
MD5_Update(&md5, in, 48);
MD5_Update(&md5, shasig, 20);
MD5_Final(&out[i * 16], &md5);
}
}
void sec_hash_64(unsigned char * out, unsigned char * in, unsigned char * salt1, unsigned char * salt2, unsigned char salt)
{
unsigned char shasig[20];
unsigned char pad[10];
SHA_CTX sha;
MD5_CTX md5;
int i;
for (i = 0; i < 4; i++)
{
memset(pad, salt + i, i + 1);
SHA1_Init(&sha);
SHA1_Update(&sha, pad, i + 1);
SHA1_Update(&sha, in, 48);
SHA1_Update(&sha, salt1, 32);
SHA1_Update(&sha, salt2, 32);
SHA1_Final(shasig, &sha);
MD5_Init(&md5);
MD5_Update(&md5, in, 48);
MD5_Update(&md5, shasig, 20);
MD5_Final(&out[i * 16], &md5);
}
}
void printmem(char *str, unsigned char *mem, unsigned int len, unsigned char hex)
{
int i=0;
printf("\n%s",str);
if(hex)
while(i<len)
printf("%x ", mem[i++]);
else
while(i<len)
printf("%c",mem[i++]);
return;
}