/****************************************************************/ /* SHA-1 Test Code */ /* (c) 2002, David Johnston */ /* Author: David Johnston */ /* Email (home): dj@deadhat.com */ /* Email (general): david.johnston@ieee.org */ /* Version 0.1 */ /* */ /* Supported message length is limited to 4096 characters */ /* ToDo: */ /* Sort out endian tolerance. Currently little endian. */ /* Remove debug code */ /****************************************************************/ #include #include #define MAX_MESSAGE_LENGTH 4096 /* #define DEBUG */ /********************************************/ /* Test Cases */ /* An array of test cases taken from the */ /* NIST SHA-1 specification. */ /********************************************/ #define NUM_TEST_CASES 2 int test_case_length[] = {3,56}; unsigned char test_cases[] = /* Test Case 1 */ { 0x61,0x62,0x63, /* Test Case 2 */ 0x61,0x62,0x63,0x64, /* abcd */ 0x62,0x63,0x64,0x65, /* bcde */ 0x63,0x64,0x65,0x66, /* cdef */ 0x64,0x65,0x66,0x67, /* defg */ 0x65,0x66,0x67,0x68, /* efgh */ 0x66,0x67,0x68,0x69, /* fghi */ 0x67,0x68,0x69,0x6a, /* ghij */ 0x68,0x69,0x6a,0x6b, /* hijk */ 0x69,0x6a,0x6b,0x6c, /* ijkl */ 0x6a,0x6b,0x6c,0x6d, /* jklm */ 0x6b,0x6c,0x6d,0x6e, /* klmn */ 0x6c,0x6d,0x6e,0x6f, /* lmno */ 0x6d,0x6e,0x6f,0x70, /* mnop */ 0x6e,0x6f,0x70,0x71 /* nopq */ }; /*****************************/ /**** Function Prototypes ****/ /*****************************/ void bitwise_xor(unsigned char *ina, unsigned char *inb, unsigned char *out); 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); void sha1 ( unsigned char *message, int message_length, unsigned char *digest ); /****************************************/ /* sha1() */ /* Performs the NIST SHA-1 algorithm */ /****************************************/ unsigned long int ft( int t, unsigned long int x, unsigned long int y, unsigned long int z ) { unsigned long int a,b,c; if (t < 20) { a = x & y; b = (~x) & z; c = a ^ b; } else if (t < 40) { c = x ^ y ^ z; } else if (t < 60) { a = x & y; b = a ^ (x & z); c = b ^ (y & z); } else if (t < 80) { c = (x ^ y) ^ z; } return c; } unsigned long int k(int t) { unsigned long int c; if (t < 20) { c = 0x5a827999; } else if (t < 40) { c = 0x6ed9eba1; } else if (t < 60) { c = 0x8f1bbcdc; } else if (t < 80) { c = 0xca62c1d6; } return c; } unsigned long int rotr(int bits, unsigned long int a) { unsigned long int c,d,e,f,g; c = (0x0001 << bits)-1; d = ~c; e = (a & d) >> 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 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 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); } /************************************************/ /* get_testcase() */ /* Copies a test case from the test case data */ /************************************************/ int get_testcase( int test_case, unsigned char *plaintext) { int i; unsigned char *ptr; ptr = test_cases; for (i=0; i< (test_case-1); i++) /* Iterate through test cases */ { ptr = ptr + test_case_length[i]; } for (i=0; i< test_case_length[test_case-1]; i++) { plaintext[i] = *ptr++; } return test_case_length[test_case-1]; } /****************************************************/ /* main() */ /* Iterate through the test cases, passing them */ /* through the sha-1 algorithm to produce test */ /* vectors */ /****************************************************/ int main() { int length; int test_case; int num_blocks; int block_remainder; int i; int j; unsigned char plaintext[MAX_MESSAGE_LENGTH+9]; unsigned char digest[20]; for (test_case = 1; test_case < (NUM_TEST_CASES+1); test_case++) { length = get_testcase(test_case, plaintext); num_blocks = length / 16; /* Calculate number of 16 byte blocks */ block_remainder = length % 16; printf ("TEST CASE %d\n",test_case); printf ("\tLength = %d\n",length); printf ("\tDATA =\n"); for (i=0;i 0) /* Print the final line */ { printf("\t\t"); for (j=0; j