/* * Copyright (C) 2007-2023 Xagasoft, All rights reserved. * * This file is part of the libbu++ library and is released under the * terms of the license contained in the file LICENSE. */ #include #include "bu/stream.h" #include "bu/sha1.h" Bu::Sha1::Sha1() : uH0( 0x67452301 ), uH1( 0xefcdab89 ), uH2( 0x98badcfe ), uH3( 0x10325476 ), uH4( 0xc3d2e1f0 ), iUnprocessedBytes( 0 ), uTotalBytes( 0 ) { reset(); } Bu::Sha1::~Sha1() { } void Bu::Sha1::reset() { uH0 = 0x67452301; uH1 = 0xefcdab89; uH2 = 0x98badcfe; uH3 = 0x10325476; uH4 = 0xc3d2e1f0; iUnprocessedBytes = 0; uTotalBytes = 0; } void Bu::Sha1::setSalt( const Bu::String & /*sSalt*/ ) { } void Bu::Sha1::addData( const void *sDataRaw, int iSize ) { const unsigned char *sData = (const unsigned char *)sDataRaw; // add these bytes to the running total uTotalBytes += iSize; // repeat until all data is processed while( iSize > 0 ) { // number of bytes required to complete block int iNeeded = 64 - iUnprocessedBytes; // number of bytes to copy (use smaller of two) int iToCopy = (iSize < iNeeded) ? iSize : iNeeded; // Copy the bytes memcpy( uBytes + iUnprocessedBytes, sData, iToCopy ); // Bytes have been copied iSize -= iToCopy; sData += iToCopy; iUnprocessedBytes += iToCopy; // there is a full block if( iUnprocessedBytes == 64 ) { process(); } } } Bu::String Bu::Sha1::getResult() { // save the message size uint32_t totalBitsL = uTotalBytes << 3; uint32_t totalBitsH = uTotalBytes >> 29; // add 0x80 to the message addData( "\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( iUnprocessedBytes > 56 ) addData( (char*)footer, 64 - iUnprocessedBytes); // how many zeros do we need int iNeededZeros = 56 - iUnprocessedBytes; // store file size (in bits) in big-endian format toBigEndian( totalBitsH, footer + iNeededZeros ); toBigEndian( totalBitsL, footer + iNeededZeros + 4 ); // finish the final block addData( (char*)footer, iNeededZeros + 8 ); Bu::String sRet( 20 ); unsigned char *digest = (unsigned char *)sRet.getStr(); // copy the digest bytes toBigEndian( uH0, digest ); toBigEndian( uH1, digest + 4 ); toBigEndian( uH2, digest + 8 ); toBigEndian( uH3, digest + 12 ); toBigEndian( uH4, digest + 16 ); // return the digest return sRet; } void Bu::Sha1::writeResult( Bu::Stream &sOut ) { sOut.write( getResult() ); } void Bu::Sha1::process() { int t; uint32_t a, b, c, d, e, K, f, W[80]; // starting values a = uH0; b = uH1; c = uH2; d = uH3; e = uH4; // copy and expand the message block for( t = 0; t < 16; t++ ) W[t] = (uBytes[t*4] << 24) +(uBytes[t*4 + 1] << 16) +(uBytes[t*4 + 2] << 8) + uBytes[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 */ uH0 += a; uH1 += b; uH2 += c; uH3 += d; uH4 += e; //printf( "Current: %08x %08x %08x %08x %08x\n",H0,H1,H2,H3,H4 ); /* all bytes have been processed */ iUnprocessedBytes = 0; } uint32_t Bu::Sha1::lrot( uint32_t x, int bits ) { return (x<>(32 - bits)); } void Bu::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; }