From 4309066dff46f52690998bbd1f60ec8b1631f142 Mon Sep 17 00:00:00 2001 From: Mike Buland Date: Thu, 19 Feb 2009 23:44:57 +0000 Subject: We have the new Bu::CryptoHash base class and Bu::Md5 is here and ready to rock. sha1 is still only a shell, I dunno if/when I'm going to implement that one. So far Bu::Md5 is 100% compatible with md5sum in all tests performed so far, in fact the test program's output is compatible with md5sum in every way (and it's so cute and little too!) Oh, minor update for stdstream and the formatter, they can handle more handy types now. --- src/cryptohash.cpp | 15 ++++ src/cryptohash.h | 22 ++++++ src/formatter.cpp | 6 ++ src/formatter.h | 1 + src/md5.cpp | 191 ++++++++++++++++++++++++++++++++++++++++++++++++ src/md5.h | 40 ++++++++++ src/sha1.cpp | 161 ++++++++++++++++++++++++++++++++++++++++ src/sha1.h | 42 +++++++++++ src/tests/md5.cpp | 27 +++++++ src/tests/stdstream.cpp | 4 +- 10 files changed, 507 insertions(+), 2 deletions(-) create mode 100644 src/cryptohash.cpp create mode 100644 src/cryptohash.h create mode 100644 src/md5.cpp create mode 100644 src/md5.h create mode 100644 src/sha1.cpp create mode 100644 src/sha1.h create mode 100644 src/tests/md5.cpp (limited to 'src') diff --git a/src/cryptohash.cpp b/src/cryptohash.cpp new file mode 100644 index 0000000..0fa2a25 --- /dev/null +++ b/src/cryptohash.cpp @@ -0,0 +1,15 @@ +#include "bu/cryptohash.h" + +Bu::CryptoHash::CryptoHash() +{ +} + +Bu::CryptoHash::~CryptoHash() +{ +} + +void Bu::CryptoHash::addData( const Bu::FString &sData ) +{ + addData( sData.getStr(), sData.getSize() ); +} + diff --git a/src/cryptohash.h b/src/cryptohash.h new file mode 100644 index 0000000..01d4634 --- /dev/null +++ b/src/cryptohash.h @@ -0,0 +1,22 @@ +#ifndef BU_CRYPTO_HASH_H +#define BU_CRYPTO_HASH_H + +#include "bu/fstring.h" + +namespace Bu +{ + class CryptoHash + { + public: + CryptoHash(); + virtual ~CryptoHash(); + + virtual void reset() = 0; + virtual void setSalt( const Bu::FString &sSalt ) = 0; + virtual void addData( const char *sData, int iSize ) = 0; + virtual void addData( const Bu::FString &sData ); + virtual FString getResult() = 0; + }; +}; + +#endif diff --git a/src/formatter.cpp b/src/formatter.cpp index 1ec3c39..36e49c8 100644 --- a/src/formatter.cpp +++ b/src/formatter.cpp @@ -159,6 +159,12 @@ Bu::Formatter &Bu::operator<<( Bu::Formatter &rOut, const char *sStr ) return rOut; } +Bu::Formatter &Bu::operator<<( Bu::Formatter &rOut, char *sStr ) +{ + rOut.writeAligned( sStr, strlen( sStr ) ); + return rOut; +} + Bu::Formatter &Bu::operator<<( Bu::Formatter &rOut, const Bu::FString &sStr ) { rOut.writeAligned( sStr ); diff --git a/src/formatter.h b/src/formatter.h index 4bab505..d9066cb 100644 --- a/src/formatter.h +++ b/src/formatter.h @@ -185,6 +185,7 @@ namespace Bu Formatter &operator<<( Formatter &rOut, const Formatter::Fmt &f ); Formatter &operator<<( Formatter &rOut, Formatter::Special s ); Formatter &operator<<( Formatter &rOut, const char *sStr ); + Formatter &operator<<( Formatter &rOut, char *sStr ); Formatter &operator<<( Formatter &rOut, const Bu::FString &sStr ); Formatter &operator<<( Formatter &rOut, signed char c ); Formatter &operator<<( Formatter &rOut, char c ); diff --git a/src/md5.cpp b/src/md5.cpp new file mode 100644 index 0000000..aa965ed --- /dev/null +++ b/src/md5.cpp @@ -0,0 +1,191 @@ +#include +#include +#include +#include "md5.h" + +// This performs a wrapping bitwise shift, kinda' fun! + +#define bit_roll( num, cnt ) \ + (((num) << (cnt)) | (((num) >> (32 - (cnt))) & ~(-1<<(cnt)))) + +//#define md5_cmn( q, a, b, x, s, t ) (bit_roll((a + q + x + t), s) + b) + +// The following are handy wrappers for the cmn function +#define md5_ff( a, b, c, d, x, s, t ) \ + (md5_cmn((b & c) | ((~b) & d), a, b, x, s, t)) + +#define md5_gg( a, b, c, d, x, s, t ) \ + (md5_cmn((b & d) | (c & (~d)), a, b, x, s, t)) + +#define md5_hh( a, b, c, d, x, s, t ) \ + (md5_cmn(b ^ c ^ d, a, b, x, s, t)) + +#define md5_ii( a, b, c, d, x, s, t ) \ + (md5_cmn(c ^ (b | (~d)), a, b, x, s, t)) + +inline long md5_cmn( long q, long a, long b, long x, long s, long t ) +{ + return bit_roll((a + q + x + t), s) + b; +} + +Bu::Md5::Md5() +{ + reset(); +} + +Bu::Md5::~Md5() +{ +} + +void Bu::Md5::reset() +{ + // These are the magic seed numbers... + + sum[0] = 1732584193; + sum[1] = -271733879; + sum[2] = -1732584194; + sum[3] = 271733878; + + iBytes = 0; + memset( inbuf, 0, 4*16 ); + iFill = 0; +} + +void Bu::Md5::setSalt( const Bu::FString & /*sSalt*/ ) +{ +} + +void Bu::Md5::addData( const char *sData, int iSize ) +{ + int iInPos = 0; + for(;;) + { + for( ; iFill < 16*4 && iInPos < iSize; iFill++, iInPos++ ) + { + inbuf[iFill>>2] |= ((long)sData[iInPos]) << ((iFill*8)%32); + } + if( iFill < 16*4 ) + break; + compBlock( inbuf, sum ); + memset( inbuf, 0, 4*16 ); + iFill = 0; + } + iBytes += iSize; +} + +Bu::FString Bu::Md5::getResult() +{ + static const char hex_tab[] = {"0123456789abcdef"}; + char str[33]; + + long lsum[4]; + memcpy( lsum, sum, 4*4 ); + long lbuf[16]; + memcpy( lbuf, inbuf, 4*16 ); + + lbuf[iFill>>2] |= 0x80 << ((iFill*8)%32); + uint64_t iBits = iBytes*8; + if( iBytes > 0 && iFill>>2 >= 14 ) + { + compBlock( lbuf, lsum ); + memset( lbuf, 0, 4*16 ); + memcpy( lbuf+14, &iBits, 8 ); + compBlock( lbuf, lsum ); + } + else + { + memcpy( lbuf+14, &iBits, 8 ); + compBlock( lbuf, lsum ); + } + + int k = 0; + for( int i = 0; i < 16; i++ ) + { + str[k++] = hex_tab[(lsum[i>>2] >> ((i%4)*8+4)) & 0xF]; + str[k++] = hex_tab[(lsum[i>>2] >> ((i%4)*8 )) & 0xF]; + } + + return Bu::FString( str, 32 ); +} + +void Bu::Md5::compBlock( long *x, long *lsum ) +{ + long a = lsum[0]; + long b = lsum[1]; + long c = lsum[2]; + long d = lsum[3]; + + a = md5_ff(a, b, c, d, x[ 0], 7 , -680876936); + d = md5_ff(d, a, b, c, x[ 1], 12, -389564586); + c = md5_ff(c, d, a, b, x[ 2], 17, 606105819); + b = md5_ff(b, c, d, a, x[ 3], 22, -1044525330); + a = md5_ff(a, b, c, d, x[ 4], 7 , -176418897); + d = md5_ff(d, a, b, c, x[ 5], 12, 1200080426); + c = md5_ff(c, d, a, b, x[ 6], 17, -1473231341); + b = md5_ff(b, c, d, a, x[ 7], 22, -45705983); + a = md5_ff(a, b, c, d, x[ 8], 7 , 1770035416); + d = md5_ff(d, a, b, c, x[ 9], 12, -1958414417); + c = md5_ff(c, d, a, b, x[10], 17, -42063); + b = md5_ff(b, c, d, a, x[11], 22, -1990404162); + a = md5_ff(a, b, c, d, x[12], 7 , 1804603682); + d = md5_ff(d, a, b, c, x[13], 12, -40341101); + c = md5_ff(c, d, a, b, x[14], 17, -1502002290); + b = md5_ff(b, c, d, a, x[15], 22, 1236535329); + + a = md5_gg(a, b, c, d, x[ 1], 5 , -165796510); + d = md5_gg(d, a, b, c, x[ 6], 9 , -1069501632); + c = md5_gg(c, d, a, b, x[11], 14, 643717713); + b = md5_gg(b, c, d, a, x[ 0], 20, -373897302); + a = md5_gg(a, b, c, d, x[ 5], 5 , -701558691); + d = md5_gg(d, a, b, c, x[10], 9 , 38016083); + c = md5_gg(c, d, a, b, x[15], 14, -660478335); + b = md5_gg(b, c, d, a, x[ 4], 20, -405537848); + a = md5_gg(a, b, c, d, x[ 9], 5 , 568446438); + d = md5_gg(d, a, b, c, x[14], 9 , -1019803690); + c = md5_gg(c, d, a, b, x[ 3], 14, -187363961); + b = md5_gg(b, c, d, a, x[ 8], 20, 1163531501); + a = md5_gg(a, b, c, d, x[13], 5 , -1444681467); + d = md5_gg(d, a, b, c, x[ 2], 9 , -51403784); + c = md5_gg(c, d, a, b, x[ 7], 14, 1735328473); + b = md5_gg(b, c, d, a, x[12], 20, -1926607734); + + a = md5_hh(a, b, c, d, x[ 5], 4 , -378558); + d = md5_hh(d, a, b, c, x[ 8], 11, -2022574463); + c = md5_hh(c, d, a, b, x[11], 16, 1839030562); + b = md5_hh(b, c, d, a, x[14], 23, -35309556); + a = md5_hh(a, b, c, d, x[ 1], 4 , -1530992060); + d = md5_hh(d, a, b, c, x[ 4], 11, 1272893353); + c = md5_hh(c, d, a, b, x[ 7], 16, -155497632); + b = md5_hh(b, c, d, a, x[10], 23, -1094730640); + a = md5_hh(a, b, c, d, x[13], 4 , 681279174); + d = md5_hh(d, a, b, c, x[ 0], 11, -358537222); + c = md5_hh(c, d, a, b, x[ 3], 16, -722521979); + b = md5_hh(b, c, d, a, x[ 6], 23, 76029189); + a = md5_hh(a, b, c, d, x[ 9], 4 , -640364487); + d = md5_hh(d, a, b, c, x[12], 11, -421815835); + c = md5_hh(c, d, a, b, x[15], 16, 530742520); + b = md5_hh(b, c, d, a, x[ 2], 23, -995338651); + + a = md5_ii(a, b, c, d, x[ 0], 6 , -198630844); + d = md5_ii(d, a, b, c, x[ 7], 10, 1126891415); + c = md5_ii(c, d, a, b, x[14], 15, -1416354905); + b = md5_ii(b, c, d, a, x[ 5], 21, -57434055); + a = md5_ii(a, b, c, d, x[12], 6 , 1700485571); + d = md5_ii(d, a, b, c, x[ 3], 10, -1894986606); + c = md5_ii(c, d, a, b, x[10], 15, -1051523); + b = md5_ii(b, c, d, a, x[ 1], 21, -2054922799); + a = md5_ii(a, b, c, d, x[ 8], 6 , 1873313359); + d = md5_ii(d, a, b, c, x[15], 10, -30611744); + c = md5_ii(c, d, a, b, x[ 6], 15, -1560198380); + b = md5_ii(b, c, d, a, x[13], 21, 1309151649); + a = md5_ii(a, b, c, d, x[ 4], 6 , -145523070); + d = md5_ii(d, a, b, c, x[11], 10, -1120210379); + c = md5_ii(c, d, a, b, x[ 2], 15, 718787259); + b = md5_ii(b, c, d, a, x[ 9], 21, -343485551); + + lsum[0] = a + lsum[0]; + lsum[1] = b + lsum[1]; + lsum[2] = c + lsum[2]; + lsum[3] = d + lsum[3]; +} + diff --git a/src/md5.h b/src/md5.h new file mode 100644 index 0000000..c548041 --- /dev/null +++ b/src/md5.h @@ -0,0 +1,40 @@ +#ifndef BU_MD5_H +#define BU_MD5_H + +#include "bu/cryptohash.h" + +namespace Bu +{ + /** + * Class for easily calculating MD5 sums of just about any data. + *@author Mike Buland + */ + class Md5 : public Bu::CryptoHash + { + public: + /** Build an MD5 sum builder. */ + Md5(); + + /** Deconstruct */ + virtual ~Md5(); + + virtual void reset(); + virtual void setSalt( const Bu::FString &sSalt ); + virtual void addData( const char *sData, int iSize ); + using Bu::CryptoHash::addData; + virtual FString getResult(); + + private: + /** + * Compute one block of input data. + */ + void compBlock( long *x, long *lsum ); + + long inbuf[16]; + long iFill; + long sum[4]; + uint64_t iBytes; + }; +}; + +#endif 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/md5.cpp b/src/tests/md5.cpp new file mode 100644 index 0000000..dea957b --- /dev/null +++ b/src/tests/md5.cpp @@ -0,0 +1,27 @@ +#include "bu/sio.h" +#include "bu/file.h" +#include "bu/md5.h" + +using Bu::sio; + +int main( int argc, char *argv[] ) +{ + argv++, argc--; + for(; *argv; argv++ ) + { + Bu::File fIn( *argv, Bu::File::Read ); + Bu::Md5 m; + + char buf[1000]; + for(;;) + { + int iRead = fIn.read( buf, 1000 ); + m.addData( buf, iRead ); + if( iRead < 1000 ) + break; + } + + sio << m.getResult() << " *" << *argv << sio.nl; + } +} + diff --git a/src/tests/stdstream.cpp b/src/tests/stdstream.cpp index cb22e22..0949a8c 100644 --- a/src/tests/stdstream.cpp +++ b/src/tests/stdstream.cpp @@ -24,8 +24,8 @@ int main() sio << 0.123 << sio.nl; sio << true << " and then " << false << sio.nl; - //for( int j = 2; j <= 36; j++ ) - // sio << "radix(" << j << ") = " << Fmt().radix( j ) << 255 << sio.nl; + for( int j = 2; j <= 36; j++ ) + sio << "radix(" << j << ") = " << Fmt().radix( j ).width( 8 ).align( Fmt::Right ) << 255 << sio.nl; return 0; } -- cgit v1.2.3