void sha1_encode( const uint8_t *data, size_t databytes, uint8_t digest[20] ) { uint64_t i, loopcount, databits, tailbytes; uint8_t datatail[128] = {0}; uint32_t H[] = { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 }; uint32_t W[80]; uint64_t idx, widx, didx = 0; /* Pre-processing of data tail (includes padding to fill out 512-bit chunk): Add bit '1' to end of message (big-endian) Add 64-bit message length in bits at very end (big-endian) */ loopcount = (databytes + 8) / 64 + 1; databits = databytes * 8; tailbytes = 64 * loopcount - databytes; datatail[0] = 0x80; datatail[tailbytes - 8] = uint8_t((databits >> 56) & 0xFF); datatail[tailbytes - 7] = uint8_t((databits >> 48) & 0xFF); datatail[tailbytes - 6] = uint8_t((databits >> 40) & 0xFF); datatail[tailbytes - 5] = uint8_t((databits >> 32) & 0xFF); datatail[tailbytes - 4] = uint8_t((databits >> 24) & 0xFF); datatail[tailbytes - 3] = uint8_t((databits >> 16) & 0xFF); datatail[tailbytes - 2] = uint8_t((databits >> 8) & 0xFF); datatail[tailbytes - 1] = uint8_t((databits >> 0) & 0xFF); /* Process each 512-bit chunk */ for( i=0; i < loopcount; ++i ) { uint32_t a = H[0]; uint32_t b = H[1]; uint32_t c = H[2]; uint32_t d = H[3]; uint32_t e = H[4]; uint32_t f=0, k=0, temp; /* Compute all elements in W */ memset( W, 0, 80 * sizeof(uint32_t) ); /* Break 512-bit chunk into sixteen 32-bit, big endian words */ for( widx=0; widx <= 15; ++widx ) { int wcount = 24; /* Copy byte-per byte from specified buffer */ while( didx < databytes && wcount >= 0 ) { W[widx] += (((uint32_t)data[didx]) << wcount); didx++; wcount -= 8; } /* Fill out W with padding as needed */ while( wcount >= 0 ) { W[widx] += (((uint32_t)datatail[didx - databytes]) << wcount); didx++; wcount -= 8; } } /* Extend the sixteen 32-bit words into eighty 32-bit words, with potential optimization from: "Improving the Performance of the Secure Hash Algorithm (SHA-1)" by Max Locktyukhin */ #define SHA1ROTATELEFT(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) for( widx = 16; widx <= 31; ++widx ) { W[widx] = SHA1ROTATELEFT( (W[widx - 3] ^ W[widx - 8] ^ W[widx - 14] ^ W[widx - 16]), 1 ); } for( widx = 32; widx <= 79; ++widx ) { W[widx] = SHA1ROTATELEFT( (W[widx - 6] ^ W[widx - 16] ^ W[widx - 28] ^ W[widx - 32]), 2 ); } /* Main loop */ for( idx=0; idx <= 79; ++idx ) { if( idx <= 19 ) { f = (b & c) | ((~b) & d); k = 0x5A827999; } else if( idx >= 20 && idx <= 39 ) { f = b ^ c ^ d; k = 0x6ED9EBA1; } else if( idx >= 40 && idx <= 59 ) { f = (b & c) | (b & d) | (c & d); k = 0x8F1BBCDC; } else if( idx >= 60 && idx <= 79 ) { f = b ^ c ^ d; k = 0xCA62C1D6; } temp = SHA1ROTATELEFT(a, 5) + f + e + k + W[idx]; e = d; d = c; c = SHA1ROTATELEFT(b, 30); b = a; a = temp; } H[0] += a; H[1] += b; H[2] += c; H[3] += d; H[4] += e; } /* Store binary digest in supplied buffer */ for( i=0; i < 5; ++i ) { digest[i * 4 + 0] = (uint8_t) (H[i] >> 24); digest[i * 4 + 1] = (uint8_t) (H[i] >> 16); digest[i * 4 + 2] = (uint8_t) (H[i] >> 8); digest[i * 4 + 3] = (uint8_t) (H[i]); } }