/****************************************************************/
/* 802.11i HMAC-SHA-1 Test Code */
/* Copyright (c) 2002, David Johnston */
/* Author: David Johnston */
/* Email (home): dj@deadhat.com */
/* Email (general): david.johnston@ieee.org */
/* Version 0.1 */
/*
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
/* */
/* This code implements the NIST HMAC-SHA-1 algorithm as used */
/* the IEEE 802.11i security spec. */
/* */
/* Supported message length is limited to 4096 characters */
/* ToDo: */
/* Sort out endian tolerance. Currently little endian. */
/****************************************************************/
#include
#include
#define MAX_MESSAGE_LENGTH 4096
/********************************************/
/* Test Cases */
/* An array of test cases taken from the */
/* 802.11i specification. */
/********************************************/
#define NUM_TEST_CASES 10
int test_case_length[] = {9,8,28,50,50,20,54,73,54,73};
unsigned char test_cases[] =
{
/* "Sample #1" */
0x53,0x61,0x6d,0x70,0x6c,0x65,0x20,0x23,0x31,
/* "Hi There" */
0x48,0x69,0x20,0x54,0x68,0x65,0x72,0x65,
/* "what do ya want for nothing?" */
0x77,0x68,0x61,0x74,0x20,0x64,0x6f,0x20,0x79,0x61,
0x20,0x77,0x61,0x6e,0x74,0x20,0x66,0x6f,0x72,0x20,
0x6e,0x6f,0x74,0x68,0x69,0x6e,0x67,0x3f,
0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,
0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,
0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,
0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,
0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,
0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,
0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,
0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,
0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,
0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,0xcd,
/* "Test With Truncation" */
0x54,0x65,0x73,0x74,0x20,0x57,0x69,0x74,0x68,0x20,0x54,0x72,0x75,0x6e,0x63,0x61,
0x74,0x69,0x6f,0x6e,
/* "Test Using Larger Than Block-Size Key - Hash Key First" */
0x54,0x65,0x73,0x74,0x20,0x55,0x73,0x69,0x6e,0x67,0x20,0x4c,0x61,0x72,0x67,0x65,
0x72,0x20,0x54,0x68,0x61,0x6e,0x20,0x42,0x6c,0x6f,0x63,0x6b,0x2d,0x53,0x69,0x7a,
0x65,0x20,0x4b,0x65,0x79,0x20,0x2d,0x20,0x48,0x61,0x73,0x68,0x20,0x4b,0x65,0x79,
0x20,0x46,0x69,0x72,0x73,0x74,
/* "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data" */
0x54,0x65,0x73,0x74,0x20,0x55,0x73,0x69,0x6e,0x67,0x20,0x4c,0x61,0x72,0x67,0x65,
0x72,0x20,0x54,0x68,0x61,0x6e,0x20,0x42,0x6c,0x6f,0x63,0x6b,0x2d,0x53,0x69,0x7a,
0x65,0x20,0x4b,0x65,0x79,0x20,0x61,0x6e,0x64,0x20,0x4c,0x61,0x72,0x67,0x65,0x72,
0x20,0x54,0x68,0x61,0x6e,0x20,0x4f,0x6e,0x65,0x20,0x42,0x6c,0x6f,0x63,0x6b,0x2d,
0x53,0x69,0x7a,0x65,0x20,0x44,0x61,0x74,0x61,
/* "Test Using Larger Than Block-Size Key - Hash Key First" */
0x54,0x65,0x73,0x74,0x20,0x55,0x73,0x69,0x6e,0x67,0x20,0x4c,0x61,0x72,0x67,0x65,
0x72,0x20,0x54,0x68,0x61,0x6e,0x20,0x42,0x6c,0x6f,0x63,0x6b,0x2d,0x53,0x69,0x7a,
0x65,0x20,0x4b,0x65,0x79,0x20,0x2d,0x20,0x48,0x61,0x73,0x68,0x20,0x4b,0x65,0x79,
0x20,0x46,0x69,0x72,0x73,0x74,
/* "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data" */
0x54,0x65,0x73,0x74,0x20,0x55,0x73,0x69,0x6e,0x67,0x20,0x4c,0x61,0x72,0x67,0x65,
0x72,0x20,0x54,0x68,0x61,0x6e,0x20,0x42,0x6c,0x6f,0x63,0x6b,0x2d,0x53,0x69,0x7a,
0x65,0x20,0x4b,0x65,0x79,0x20,0x61,0x6e,0x64,0x20,0x4c,0x61,0x72,0x67,0x65,0x72,
0x20,0x54,0x68,0x61,0x6e,0x20,0x4f,0x6e,0x65,0x20,0x42,0x6c,0x6f,0x63,0x6b,0x2d,
0x53,0x69,0x7a,0x65,0x20,0x44,0x61,0x74,0x61
};
int key_lengths[] =
{
64, 20,4,20,25,20,80,80,80,80
};
unsigned char keys[] =
{
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,
0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,0x0b,
0x0b,0x0b,0x0b,0x0b,
0x4a,0x65,0x66,0x65, /* "Jefe" */
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,
0x0b,0x0c,0x0d,0x0e,0x0f,0x10,0x11,0x12,0x13,0x14,
0x15,0x16,0x17,0x18,0x19,
0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,
0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
};
/*****************************/
/**** Function Prototypes ****/
/*****************************/
unsigned long int ft(
int t,
unsigned long int x,
unsigned long int y,
unsigned long int z
);
int get_testcase( int test_case,
unsigned char *plaintext,
unsigned char *key,
int *key_length_ptr);
void sha1 (
unsigned char *message,
int message_length,
unsigned char *digest
);
/**************************/
/* Debug out */
/**************************/
#ifdef HMAC_DEBUG
debug_out(
unsigned char *label,
unsigned char *data,
int data_length
)
{
int i,j;
int num_blocks;
int block_remainder;
num_blocks = data_length / 16;
block_remainder = data_length % 16;
printf("%s\n",label);
for (i=0; i< num_blocks;i++)
{
printf("\t");
for (j=0; j< 16;j++)
{
printf("%02x ", data[j + (i*16)]);
}
printf("\n");
}
if (block_remainder > 0)
{
printf("\t");
for (j=0; j> bits;
f = (a & c) << (32 - bits);
g = e | f;
return (g & 0xffffffff );
}
unsigned long int rotl(int bits, unsigned long int a)
{
unsigned long int c,d,e,f,g;
c = (0x0001 << (32-bits))-1;
d = ~c;
e = (a & c) << bits;
f = (a & d) >> (32 - bits);
g = e | f;
return (g & 0xffffffff );
}
void sha1 (
unsigned char *message,
int message_length,
unsigned char *digest
)
{
int i;
int num_blocks;
int block_remainder;
int padded_length;
unsigned long int l;
unsigned long int t;
unsigned long int h[5];
unsigned long int a,b,c,d,e;
unsigned long int w[80];
unsigned long int temp;
#ifdef SHA1_DEBUG
int x,y;
#endif
/* Calculate the number of 512 bit blocks */
padded_length = message_length + 8; /* Add length for l */
padded_length = padded_length + 1; /* Add the 0x01 bit postfix */
l = message_length * 8;
num_blocks = padded_length / 64;
block_remainder = padded_length % 64;
if (block_remainder > 0)
{
num_blocks++;
}
padded_length = padded_length + (64 - block_remainder);
/* clear the padding field */
for (i = message_length; i < (num_blocks * 64); i++)
{
message[i] = 0x00;
}
/* insert b1 padding bit */
message[message_length] = 0x80;
/* Insert l */
message[(num_blocks*64)-1] = (unsigned char)( l & 0xff);
message[(num_blocks*64)-2] = (unsigned char)((l >> 8) & 0xff);
message[(num_blocks*64)-3] = (unsigned char)((l >> 16) & 0xff);
message[(num_blocks*64)-4] = (unsigned char)((l >> 24) & 0xff);
/* Set initial hash state */
h[0] = 0x67452301;
h[1] = 0xefcdab89;
h[2] = 0x98badcfe;
h[3] = 0x10325476;
h[4] = 0xc3d2e1f0;
#ifdef SHA1_DEBUG
printf("INITIAL message_length = %d\n", message_length);
printf("INITIAL padded_length = %d\n", padded_length);
printf("INITIAL num_blocks = %d\n", num_blocks);
for (x=0;x> 8) & 0xff);
digest[1] = (unsigned char) ((h[0] >> 16) & 0xff);
digest[0] = (unsigned char) ((h[0] >> 24) & 0xff);
digest[7] = (unsigned char) ( h[1] & 0xff);
digest[6] = (unsigned char) ((h[1] >> 8) & 0xff);
digest[5] = (unsigned char) ((h[1] >> 16) & 0xff);
digest[4] = (unsigned char) ((h[1] >> 24) & 0xff);
digest[11] = (unsigned char) ( h[2] & 0xff);
digest[10] = (unsigned char) ((h[2] >> 8) & 0xff);
digest[9] = (unsigned char) ((h[2] >> 16) & 0xff);
digest[8] = (unsigned char) ((h[2] >> 24) & 0xff);
digest[15] = (unsigned char) ( h[3] & 0xff);
digest[14] = (unsigned char) ((h[3] >> 8) & 0xff);
digest[13] = (unsigned char) ((h[3] >> 16) & 0xff);
digest[12] = (unsigned char) ((h[3] >> 24) & 0xff);
digest[19] = (unsigned char) ( h[4] & 0xff);
digest[18] = (unsigned char) ((h[4] >> 8) & 0xff);
digest[17] = (unsigned char) ((h[4] >> 16) & 0xff);
digest[16] = (unsigned char) ((h[4] >> 24) & 0xff);
}
/******************************************************/
/* hmac-sha1() */
/* Performs the hmac-sha1 keyed secure hash algorithm */
/******************************************************/
void hmac_sha1(
unsigned char *key,
int key_length,
unsigned char *data,
int data_length,
unsigned char *digest
)
{
int b = 64; /* blocksize */
unsigned char ipad = 0x36;
unsigned char opad = 0x5c;
unsigned char k0[64];
unsigned char k0xorIpad[64];
unsigned char step7data[64];
unsigned char step5data[MAX_MESSAGE_LENGTH+128];
unsigned char step8data[64+20];
int i;
for (i=0; i<64; i++)
{
k0[i] = 0x00;
}
if (key_length != b) /* Step 1 */
{
/* Step 2 */
if (key_length > b)
{
sha1(key, key_length, digest);
for (i=0;i<20;i++)
{
k0[i]=digest[i];
}
}
else if (key_length < b) /* Step 3 */
{
for (i=0; i 0) /* Print the final line */
{
printf("\t\t");
for (j=0; j 0) /* Print the final line */
{
printf("\t\t");
for (j=0; j