| /* | |
| sha1.cpp - source code of | |
| ============ | |
| SHA-1 in C++ | |
| ============ | |
| 100% Public Domain. | |
| Original C Code | |
| -- Steve Reid <steve@edmweb.com> | |
| Small changes to fit into bglibs | |
| -- Bruce Guenter <bruce@untroubled.org> | |
| Translation to simpler C++ Code | |
| -- Volker Grabsch <vog@notjusthosting.com> | |
| Fixing bugs and improving style | |
| -- Eugene Hopkinson <slowriot at voxelstorm dot com> | |
| */ | |
| #include "sha1.h" | |
| #include <sstream> | |
| #include <iomanip> | |
| #include <fstream> | |
| /* Help macros */ | |
| #define SHA1_ROL(value, bits) (((value) << (bits)) | (((value) & 0xffffffff) >> (32 - (bits)))) | |
| #define SHA1_BLK(i) (block[i&15] = SHA1_ROL(block[(i+13)&15] ^ block[(i+8)&15] ^ block[(i+2)&15] ^ block[i&15],1)) | |
| /* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ | |
| #define SHA1_R0(v,w,x,y,z,i) z += ((w&(x^y))^y) + block[i] + 0x5a827999 + SHA1_ROL(v,5); w=SHA1_ROL(w,30); | |
| #define SHA1_R1(v,w,x,y,z,i) z += ((w&(x^y))^y) + SHA1_BLK(i) + 0x5a827999 + SHA1_ROL(v,5); w=SHA1_ROL(w,30); | |
| #define SHA1_R2(v,w,x,y,z,i) z += (w^x^y) + SHA1_BLK(i) + 0x6ed9eba1 + SHA1_ROL(v,5); w=SHA1_ROL(w,30); | |
| #define SHA1_R3(v,w,x,y,z,i) z += (((w|x)&y)|(w&x)) + SHA1_BLK(i) + 0x8f1bbcdc + SHA1_ROL(v,5); w=SHA1_ROL(w,30); | |
| #define SHA1_R4(v,w,x,y,z,i) z += (w^x^y) + SHA1_BLK(i) + 0xca62c1d6 + SHA1_ROL(v,5); w=SHA1_ROL(w,30); | |
| SHA1::SHA1() | |
| { | |
| reset(); | |
| } | |
| void SHA1::update(const std::string &s) | |
| { | |
| std::istringstream is(s); | |
| update(is); | |
| } | |
| void SHA1::update(std::istream &is) | |
| { | |
| std::string rest_of_buffer; | |
| read(is, rest_of_buffer, BLOCK_BYTES - buffer.size()); | |
| buffer += rest_of_buffer; | |
| while (is) | |
| { | |
| uint32_t block[BLOCK_INTS]; | |
| buffer_to_block(buffer, block); | |
| transform(block); | |
| read(is, buffer, BLOCK_BYTES); | |
| } | |
| } | |
| /* | |
| * Add padding and return the message digest. | |
| */ | |
| std::string SHA1::final() | |
| { | |
| /* Total number of hashed bits */ | |
| uint64_t total_bits = (transforms*BLOCK_BYTES + buffer.size()) * 8; | |
| /* Padding */ | |
| buffer += 0x80; | |
| unsigned int orig_size = buffer.size(); | |
| while (buffer.size() < BLOCK_BYTES) | |
| { | |
| buffer += (char)0x00; | |
| } | |
| uint32_t block[BLOCK_INTS]; | |
| buffer_to_block(buffer, block); | |
| if (orig_size > BLOCK_BYTES - 8) | |
| { | |
| transform(block); | |
| for (unsigned int i = 0; i < BLOCK_INTS - 2; i++) | |
| { | |
| block[i] = 0; | |
| } | |
| } | |
| /* Append total_bits, split this uint64_t into two uint32_t */ | |
| block[BLOCK_INTS - 1] = total_bits; | |
| block[BLOCK_INTS - 2] = (total_bits >> 32); | |
| transform(block); | |
| /* Hex std::string */ | |
| std::ostringstream result; | |
| for (unsigned int i = 0; i < DIGEST_INTS; i++) | |
| { | |
| result << std::hex << std::setfill('0') << std::setw(8); | |
| result << (digest[i] & 0xffffffff); | |
| } | |
| /* Reset for next run */ | |
| reset(); | |
| return result.str(); | |
| } | |
| std::string SHA1::from_file(const std::string &filename) | |
| { | |
| std::ifstream stream(filename.c_str(), std::ios::binary); | |
| SHA1 checksum; | |
| checksum.update(stream); | |
| return checksum.final(); | |
| } | |
| void SHA1::reset() | |
| { | |
| /* SHA1 initialization constants */ | |
| digest[0] = 0x67452301; | |
| digest[1] = 0xefcdab89; | |
| digest[2] = 0x98badcfe; | |
| digest[3] = 0x10325476; | |
| digest[4] = 0xc3d2e1f0; | |
| /* Reset counters */ | |
| transforms = 0; | |
| buffer = ""; | |
| } | |
| /* | |
| * Hash a single 512-bit block. This is the core of the algorithm. | |
| */ | |
| void SHA1::transform(uint32_t block[BLOCK_BYTES]) | |
| { | |
| /* Copy digest[] to working vars */ | |
| uint32_t a = digest[0]; | |
| uint32_t b = digest[1]; | |
| uint32_t c = digest[2]; | |
| uint32_t d = digest[3]; | |
| uint32_t e = digest[4]; | |
| /* 4 rounds of 20 operations each. Loop unrolled. */ | |
| SHA1_R0(a,b,c,d,e, 0); | |
| SHA1_R0(e,a,b,c,d, 1); | |
| SHA1_R0(d,e,a,b,c, 2); | |
| SHA1_R0(c,d,e,a,b, 3); | |
| SHA1_R0(b,c,d,e,a, 4); | |
| SHA1_R0(a,b,c,d,e, 5); | |
| SHA1_R0(e,a,b,c,d, 6); | |
| SHA1_R0(d,e,a,b,c, 7); | |
| SHA1_R0(c,d,e,a,b, 8); | |
| SHA1_R0(b,c,d,e,a, 9); | |
| SHA1_R0(a,b,c,d,e,10); | |
| SHA1_R0(e,a,b,c,d,11); | |
| SHA1_R0(d,e,a,b,c,12); | |
| SHA1_R0(c,d,e,a,b,13); | |
| SHA1_R0(b,c,d,e,a,14); | |
| SHA1_R0(a,b,c,d,e,15); | |
| SHA1_R1(e,a,b,c,d,16); | |
| SHA1_R1(d,e,a,b,c,17); | |
| SHA1_R1(c,d,e,a,b,18); | |
| SHA1_R1(b,c,d,e,a,19); | |
| SHA1_R2(a,b,c,d,e,20); | |
| SHA1_R2(e,a,b,c,d,21); | |
| SHA1_R2(d,e,a,b,c,22); | |
| SHA1_R2(c,d,e,a,b,23); | |
| SHA1_R2(b,c,d,e,a,24); | |
| SHA1_R2(a,b,c,d,e,25); | |
| SHA1_R2(e,a,b,c,d,26); | |
| SHA1_R2(d,e,a,b,c,27); | |
| SHA1_R2(c,d,e,a,b,28); | |
| SHA1_R2(b,c,d,e,a,29); | |
| SHA1_R2(a,b,c,d,e,30); | |
| SHA1_R2(e,a,b,c,d,31); | |
| SHA1_R2(d,e,a,b,c,32); | |
| SHA1_R2(c,d,e,a,b,33); | |
| SHA1_R2(b,c,d,e,a,34); | |
| SHA1_R2(a,b,c,d,e,35); | |
| SHA1_R2(e,a,b,c,d,36); | |
| SHA1_R2(d,e,a,b,c,37); | |
| SHA1_R2(c,d,e,a,b,38); | |
| SHA1_R2(b,c,d,e,a,39); | |
| SHA1_R3(a,b,c,d,e,40); | |
| SHA1_R3(e,a,b,c,d,41); | |
| SHA1_R3(d,e,a,b,c,42); | |
| SHA1_R3(c,d,e,a,b,43); | |
| SHA1_R3(b,c,d,e,a,44); | |
| SHA1_R3(a,b,c,d,e,45); | |
| SHA1_R3(e,a,b,c,d,46); | |
| SHA1_R3(d,e,a,b,c,47); | |
| SHA1_R3(c,d,e,a,b,48); | |
| SHA1_R3(b,c,d,e,a,49); | |
| SHA1_R3(a,b,c,d,e,50); | |
| SHA1_R3(e,a,b,c,d,51); | |
| SHA1_R3(d,e,a,b,c,52); | |
| SHA1_R3(c,d,e,a,b,53); | |
| SHA1_R3(b,c,d,e,a,54); | |
| SHA1_R3(a,b,c,d,e,55); | |
| SHA1_R3(e,a,b,c,d,56); | |
| SHA1_R3(d,e,a,b,c,57); | |
| SHA1_R3(c,d,e,a,b,58); | |
| SHA1_R3(b,c,d,e,a,59); | |
| SHA1_R4(a,b,c,d,e,60); | |
| SHA1_R4(e,a,b,c,d,61); | |
| SHA1_R4(d,e,a,b,c,62); | |
| SHA1_R4(c,d,e,a,b,63); | |
| SHA1_R4(b,c,d,e,a,64); | |
| SHA1_R4(a,b,c,d,e,65); | |
| SHA1_R4(e,a,b,c,d,66); | |
| SHA1_R4(d,e,a,b,c,67); | |
| SHA1_R4(c,d,e,a,b,68); | |
| SHA1_R4(b,c,d,e,a,69); | |
| SHA1_R4(a,b,c,d,e,70); | |
| SHA1_R4(e,a,b,c,d,71); | |
| SHA1_R4(d,e,a,b,c,72); | |
| SHA1_R4(c,d,e,a,b,73); | |
| SHA1_R4(b,c,d,e,a,74); | |
| SHA1_R4(a,b,c,d,e,75); | |
| SHA1_R4(e,a,b,c,d,76); | |
| SHA1_R4(d,e,a,b,c,77); | |
| SHA1_R4(c,d,e,a,b,78); | |
| SHA1_R4(b,c,d,e,a,79); | |
| /* Add the working vars back into digest[] */ | |
| digest[0] += a; | |
| digest[1] += b; | |
| digest[2] += c; | |
| digest[3] += d; | |
| digest[4] += e; | |
| /* Count the number of transformations */ | |
| transforms++; | |
| } | |
| void SHA1::buffer_to_block(const std::string &buffer, uint32_t block[BLOCK_INTS]) | |
| { | |
| /* Convert the std::string (byte buffer) to a uint32_t array (MSB) */ | |
| for (unsigned int i = 0; i < BLOCK_INTS; i++) | |
| { | |
| block[i] = (buffer[4*i+3] & 0xff) | |
| | (buffer[4*i+2] & 0xff)<<8 | |
| | (buffer[4*i+1] & 0xff)<<16 | |
| | (buffer[4*i+0] & 0xff)<<24; | |
| } | |
| } | |
| void SHA1::read(std::istream &is, std::string &s, size_t max) | |
| { | |
| char* sbuf = new char[max]; | |
| is.read(sbuf, max); | |
| s.assign(sbuf, is.gcount()); | |
| delete[] sbuf; | |
| } | |
| std::string sha1(const std::string &string) | |
| { | |
| SHA1 checksum; | |
| checksum.update(string); | |
| return checksum.final(); | |
| } |