/* sha1.cpp Copyright (c) 2005 Michael D. Leonhard http://tamale.net/ This file is licensed under the terms described in the accompanying LICENSE file. */ #include #include #include #include #include "sha1.h" // print out memory in hexadecimal void SHA1::hexPrinter( unsigned char* c, int l ) { assert( c ); assert( l > 0 ); while( l > 0 ) { printf( " %02x", *c ); l--; c++; } } // circular left bit rotation. MSB wraps around to LSB Uint32 SHA1::lrot( Uint32 x, int bits ) { return (x<>(32 - bits)); }; // Save a 32-bit unsigned integer to memory, in big-endian order void SHA1::storeBigEndianUint32( unsigned char* byte, Uint32 num ) { assert( byte ); byte[0] = (unsigned char)(num>>24); byte[1] = (unsigned char)(num>>16); byte[2] = (unsigned char)(num>>8); byte[3] = (unsigned char)num; } // Constructor ******************************************************* SHA1::SHA1() { // make sure that the data type is the right size assert( sizeof( Uint32 ) * 5 == 20 ); // initialize H0 = 0x67452301; H1 = 0xefcdab89; H2 = 0x98badcfe; H3 = 0x10325476; H4 = 0xc3d2e1f0; unprocessedBytes = 0; size = 0; } // Destructor ******************************************************** SHA1::~SHA1() { // erase data H0 = H1 = H2 = H3 = H4 = 0; for( int c = 0; c < 64; c++ ) bytes[c] = 0; unprocessedBytes = size = 0; } // process *********************************************************** void SHA1::process() { assert( unprocessedBytes == 64 ); //printf( "process: " ); hexPrinter( bytes, 64 ); printf( "\n" ); int t; Uint32 a, b, c, d, e, K, f, W[80]; // starting values a = H0; b = H1; c = H2; d = H3; e = H4; // copy and expand the message block for( t = 0; t < 16; t++ ) W[t] = (bytes[t*4] << 24) +(bytes[t*4 + 1] << 16) +(bytes[t*4 + 2] << 8) + bytes[t*4 + 3]; for(; t< 80; t++ ) W[t] = lrot( W[t-3]^W[t-8]^W[t-14]^W[t-16], 1 ); /* main loop */ Uint32 temp; for( t = 0; t < 80; t++ ) { if( t < 20 ) { K = 0x5a827999; f = (b & c) | ((b ^ 0xFFFFFFFF) & d);//TODO: try using ~ } else if( t < 40 ) { K = 0x6ed9eba1; f = b ^ c ^ d; } else if( t < 60 ) { K = 0x8f1bbcdc; f = (b & c) | (b & d) | (c & d); } else { K = 0xca62c1d6; f = b ^ c ^ d; } temp = lrot(a,5) + f + e + W[t] + K; e = d; d = c; c = lrot(b,30); b = a; a = temp; //printf( "t=%d %08x %08x %08x %08x %08x\n",t,a,b,c,d,e ); } /* add variables */ H0 += a; H1 += b; H2 += c; H3 += d; H4 += e; //printf( "Current: %08x %08x %08x %08x %08x\n",H0,H1,H2,H3,H4 ); /* all bytes have been processed */ unprocessedBytes = 0; } // addBytes ********************************************************** void SHA1::addBytes( const char* data, int num ) { assert( data ); assert( num > 0 ); // add these bytes to the running total size += num; // repeat until all data is processed while( num > 0 ) { // number of bytes required to complete block int needed = 64 - unprocessedBytes; assert( needed > 0 ); // number of bytes to copy (use smaller of two) int toCopy = (num < needed) ? num : needed; // Copy the bytes memcpy( bytes + unprocessedBytes, data, toCopy ); // Bytes have been copied num -= toCopy; data += toCopy; unprocessedBytes += toCopy; // there is a full block if( unprocessedBytes == 64 ) process(); } } // digest ************************************************************ unsigned char* SHA1::getDigest() { // save the message size Uint32 totalBitsL = size << 3; Uint32 totalBitsH = size >> 29; // add 0x80 to the message addBytes( "\x80", 1 ); unsigned char footer[64] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; // block has no room for 8-byte filesize, so finish it if( unprocessedBytes > 56 ) addBytes( (char*)footer, 64 - unprocessedBytes); assert( unprocessedBytes <= 56 ); // how many zeros do we need int neededZeros = 56 - unprocessedBytes; // store file size (in bits) in big-endian format storeBigEndianUint32( footer + neededZeros , totalBitsH ); storeBigEndianUint32( footer + neededZeros + 4, totalBitsL ); // finish the final block addBytes( (char*)footer, neededZeros + 8 ); // allocate memory for the digest bytes unsigned char* digest = (unsigned char*)malloc( 20 ); // copy the digest bytes storeBigEndianUint32( digest, H0 ); storeBigEndianUint32( digest + 4, H1 ); storeBigEndianUint32( digest + 8, H2 ); storeBigEndianUint32( digest + 12, H3 ); storeBigEndianUint32( digest + 16, H4 ); // return the digest return digest; }