/*************************************************************************** * Copyright (c) 2002-2010, Broadcom Corporation * All Rights Reserved * Confidential Property of Broadcom Corporation * * THIS SOFTWARE MAY ONLY BE USED SUBJECT TO AN EXECUTED SOFTWARE LICENSE * AGREEMENT BETWEEN THE USER AND BROADCOM. YOU HAVE NO RIGHT TO USE OR * EXPLOIT THIS MATERIAL EXCEPT SUBJECT TO THE TERMS OF SUCH AN AGREEMENT. * * Filename: sha1.c * ***************************************************************************/ #include "sha1o.h" #define OPTIMIZE_ROT 1 /* Following optimizations were performed : F01 was replaced by shorter version from wikipedia F03 was replaced by shorter version from wikipedia ROTL was replaced by ROT1 ROT5 and ROT30 which at expense of some size save 2 operations per ROTL call All functions were brought in to one file which should enable better optimization by compiler */ void SHA1Compute_ram( uint8 * image_ptr, int len, uint32 * digest ); #if 0 static inline uint32 F01( uint32 x, uint32 y, uint32 z ) { return (x & y) | ( (~x) & z ); } #else static inline uint32 F01( uint32 x, uint32 y, uint32 z ) { return (((y ^ z) & x) ^ z); } #endif #if 0 static inline uint32 F03( uint32 x, uint32 y, uint32 z ) { return (x & y) | (x & z) | (y & z); } #else static inline uint32 F03( uint32 x, uint32 y, uint32 z ) { return (((x | y) & z) | (x & y)); } #endif static inline uint32 F24( uint32 x, uint32 y, uint32 z ) { return (x ^ y ^ z); } #if OPTIMIZE_ROT == 0 static inline uint32 ROTL( uint32 x, uint32 n ) { return (x << n) | (x >> (32 - n)); } #else static inline uint32 ROTL1( uint32 x ) { return (x << 1) | (x >> (31)); } static inline uint32 ROTL5( uint32 x ) { return (x << 5) | (x >> (27)); } static inline uint32 ROTL30( uint32 x ) { return (x << 30) | (x >> (2)); } #endif static inline void WsubT (uint32 block []) { uint32 tmp; int i; #if OPTIMIZE_ROT == 0 tmp = ROTL ((block[0] ^ block [2] ^ block [8] ^ block [13]), 1); #else tmp = ROTL1 ((block[0] ^ block [2] ^ block [8] ^ block [13])); #endif for (i = 0; i < 15; i++) { block[i] = block[i+1]; } block[15] = tmp; } static inline void TBlock(uint32 * T, uint32 * block, int i) { if( i < 16 ) { *T = block[i]; } else { WsubT(block); *T = block[15]; } } void SHA1Transform( uint32 digest[], uint32 block[] ) { int i; uint32 a, b, c, d, e, T; a = digest[0]; b = digest[1]; c = digest[2]; d = digest[3]; e = digest[4]; for( i = 0; i < 80; i++ ) { TBlock(&T,block,i); #if OPTIMIZE_ROT == 0 T += ROTL( a, 5 ) + e; #else T += ROTL5( a ) + e; #endif if( i < 20 ) { T += F01( b, c, d ) + 0x5A827999; } else if( i < 40 ) { T += F24( b, c, d ) + 0x6ED9EBA1; } else if( i < 60 ) { T += F03( b, c, d ) + 0x8F1BBCDC; } else { T += F24( b, c, d ) + 0xCA62C1D6; } e = d; d = c; #if OPTIMIZE_ROT == 0 c = ROTL( b, 30 ); #else c = ROTL30( b ); #endif b = a; a = T; } digest[0] += a; digest[1] += b; digest[2] += c; digest[3] += d; digest[4] += e; } /* image_ptr must be aligned on 4 bytes boundary since it is accessed as uint32 type. len parameter is specifies message length in bits. To obtain this number multiply message length in bytes by 8. This function works on data of arbitrary length up to 2^31/8 bytes or up to 268435456 bytes. */ void SHA1Compute_ram( uint8 * image_ptr, int len, uint32 * digest ) { uint32 data [16]; //tmp; unsigned long temp; int fullLen = len; /* save full length */ int i; digest[0] = 0x67452301; digest[1] = 0xEFCDAB89; digest[2] = 0x98BADCFE; digest[3] = 0x10325476; digest[4] = 0xC3D2E1F0; /* * Note: len is in number of bits, not bytes */ while( (len / 512) >= 1 ) { /* Determine if needed */ for (i = 0; i < 16; i++) { temp = *((unsigned long *) image_ptr); #ifdef SHA1_ENDIAN_SWAP data[i] = (temp << 24) | (temp >> 24) | ((temp >> 8) & 0xff00) | ((temp & 0xff00) << 8); #else data[i] = temp; #endif image_ptr += 4; } /* end of section */ SHA1Transform( digest, data ); len -= 512; } /* pick up whole words */ i = 0; while( (len / 32) >= 1){ temp = *((unsigned long *) image_ptr); #ifdef SHA1_ENDIAN_SWAP data[i] = (temp << 24) | (temp >> 24) | ((temp >> 8) & 0xff00) | ((temp & 0xff00) << 8); #else data[i] = temp; #endif i ++; image_ptr += 4; len -= 32; } /* pick up remaining bytes, read 4 bytes but discard unused */ if(len > 0){ temp = *((unsigned long *) image_ptr); #ifdef SHA1_ENDIAN_SWAP temp = (temp << 24) | ((temp >> 8) & 0xff00) | ((temp & 0xff00) << 8); #endif temp = (temp >> (32 - len)) << (32 - len); data[i] = temp | (0x80 << (24 - len)); }else{ data[i] = 0x80000000; } /* fill remainder if possible but leave room for lenght */ for(i++; i < 14; i++){ data[i] = 0x00000000; } /* at this point i can be 14 or 15 or 16*/ if(i != 14){ if(i == 15) data[i] = 0x00000000; SHA1Transform( digest, data ); for(i = 0; i < 14; i++){ data[i] = 0x00000000; } } /* 64 bit size */ data[i] = 0x00000000; i++; data[i] = fullLen; SHA1Transform( digest, data ); }