From a67fdaa1ef1e3a5eea88d19e327c05330998e8aa Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Tue, 31 Oct 2006 05:41:13 +0000 Subject: Added an sha1 class... --- src/sha1.cpp | 161 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/sha1.h | 42 ++++++++++++++ src/tests/sha1.cpp | 44 +++++++++++++++ 3 files changed, 247 insertions(+) create mode 100644 src/sha1.cpp create mode 100644 src/sha1.h create mode 100644 src/tests/sha1.cpp diff --git a/src/sha1.cpp b/src/sha1.cpp new file mode 100644 index 0000000..8270c3b --- /dev/null +++ b/src/sha1.cpp @@ -0,0 +1,161 @@ +#include +#include +#include + +#include "sha1.h" + +Sha1::Sha1() : + H0( 0x67452301 ), + H1( 0xefcdab89 ), + H2( 0x98badcfe ), + H3( 0x10325476 ), + H4( 0xc3d2e1f0 ), + unprocessedBytes( 0 ), + size( 0 ) +{ +} + +Sha1::~Sha1() +{ +} + +void Sha1::process() +{ + int t; + uint32_t 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_t temp; + for( t = 0; t < 80; t++ ) + { + if( t < 20 ) { + K = 0x5a827999; + f = (b & c) | ((~b) & d); + } 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; +} + +void Sha1::update( const char* data, int num ) +{ + // 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; + + // 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(); + } +} + +unsigned char* Sha1::getDigest() +{ + // save the message size + uint32_t totalBitsL = size << 3; + uint32_t totalBitsH = size >> 29; + + // add 0x80 to the message + update( "\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 ) + update( (char*)footer, 64 - unprocessedBytes); + + // how many zeros do we need + int neededZeros = 56 - unprocessedBytes; + + // store file size (in bits) in big-endian format + toBigEndian( totalBitsH, footer + neededZeros ); + toBigEndian( totalBitsL, footer + neededZeros + 4 ); + + // finish the final block + update( (char*)footer, neededZeros + 8 ); + + // allocate memory for the digest bytes + unsigned char* digest = new unsigned char[20]; + + // copy the digest bytes + toBigEndian( H0, digest ); + toBigEndian( H1, digest + 4 ); + toBigEndian( H2, digest + 8 ); + toBigEndian( H3, digest + 12 ); + toBigEndian( H4, digest + 16 ); + + // return the digest + return digest; +} + +uint32_t Sha1::lrot( uint32_t x, int bits ) +{ + return (x<>(32 - bits)); +}; + +void Sha1::toBigEndian( uint32_t num, unsigned char* byte ) +{ + byte[0] = (unsigned char)(num>>24); + byte[1] = (unsigned char)(num>>16); + byte[2] = (unsigned char)(num>>8); + byte[3] = (unsigned char)num; +} + diff --git a/src/sha1.h b/src/sha1.h new file mode 100644 index 0000000..ab6081d --- /dev/null +++ b/src/sha1.h @@ -0,0 +1,42 @@ +/* sha1.h + +Copyright (c) 2005 Michael D. Leonhard + +http://tamale.net/ + +This file is licensed under the terms described in the +accompanying LICENSE file. +*/ + +#ifndef SHA1_H +#define SHA1_H + +#include + +/** + * Calculates SHA-1 sums. This is based strongly on code from Michael D. + * Leonhard who released his code under the terms of the MIT license, thank you! + */ +class Sha1 +{ +public: + Sha1(); + ~Sha1(); + + void update( const char* data, int num ); + unsigned char* getDigest(); + + // utility methods + static uint32_t lrot( uint32_t x, int bits ); + static void toBigEndian( uint32_t in, unsigned char* out ); + +private: + // fields + uint32_t H0, H1, H2, H3, H4; + unsigned char bytes[64]; + int unprocessedBytes; + uint32_t size; + void process(); +}; + +#endif diff --git a/src/tests/sha1.cpp b/src/tests/sha1.cpp new file mode 100644 index 0000000..51c5104 --- /dev/null +++ b/src/tests/sha1.cpp @@ -0,0 +1,44 @@ +#include "sha1.h" +#include "file.h" + +#define BS 1024 + +int main( int argc, char *argv[] ) +{ + argc--; argv++; + + if( argc == 0 ) + { + printf("Provide a filename.\n"); + return 0; + } + + char buf[BS]; + + Sha1 s; + File fin( *argv, "rb" ); + for(;;) + { + int nRead = fin.read( buf, BS ); + if( nRead == 0 ) + break; + + s.update( buf, nRead ); + if( nRead < BS ) + break; + } + + unsigned char *dig = s.getDigest(); + + char val[]={"0123456789ABCDEF"}; + + for( int j = 0; j < 20; j++ ) + { + putchar( val[dig[j]>>4] ); + putchar( val[dig[j]&0x0F] ); + } + putchar('\n'); + + delete[] dig; +} + -- cgit v1.2.3