#include "stdafx.h" #include "SHA1.h" #include namespace zl { namespace util { static const int kSHA1DigestSize = 20; SHA1::SHA1() { reset(); } SHA1::~SHA1() { } // SHA1Init - Initialize new context. void SHA1::reset() { // SHA1 initialization constants. context_.state[0] = 0x67452301; context_.state[1] = 0xEFCDAB89; context_.state[2] = 0x98BADCFE; context_.state[3] = 0x10325476; context_.state[4] = 0xC3D2E1F0; context_.count[0] = context_.count[1] = 0; } #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) // blk0() and blk() perform the initial expand. // I got the idea of expanding during the round function from SSLeay #define blk0(i) (block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) | \ (rol(block->l[i], 8) & 0x00FF00FF)) #define blk(i) (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ \ block->l[(i + 8) & 15] ^ block->l[(i + 2) & 15] ^ block->l[i & 15], 1)) // (R0+R1), R2, R3, R4 are the different operations used in SHA1. #define R0(v, w, x, y, z, i) \ z += ((w & (x ^ y)) ^ y) + blk0(i) + 0x5A827999 + rol(v, 5); \ w = rol(w, 30); #define R1(v, w, x, y, z, i) \ z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \ w = rol(w, 30); #define R2(v, w, x, y, z, i) \ z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5);\ w = rol(w, 30); #define R3(v, w, x, y, z, i) \ z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \ w = rol(w, 30); #define R4(v, w, x, y, z, i) \ z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \ w = rol(w, 30); // Hash a single 512-bit block. This is the core of the algorithm. void SHA1::sha1Transform(uint32_t state[5], const uint8_t buffer[64]) { union CHAR64LONG16 { uint8_t c[64]; uint32_t l[16]; }; // Note(fbarchard): This option does modify the user's data buffer. CHAR64LONG16* block = const_cast(reinterpret_cast(buffer)); // Copy context_.state[] to working vars. uint32_t a = state[0]; uint32_t b = state[1]; uint32_t c = state[2]; uint32_t d = state[3]; uint32_t e = state[4]; // 4 rounds of 20 operations each. Loop unrolled. // Note(fbarchard): The following has lint warnings for multiple ; on // a line and no space after , but is left as-is to be similar to the // original code. R0(a, b, c, d, e, 0); R0(e, a, b, c, d, 1); R0(d, e, a, b, c, 2); R0(c, d, e, a, b, 3); R0(b, c, d, e, a, 4); R0(a, b, c, d, e, 5); R0(e, a, b, c, d, 6); R0(d, e, a, b, c, 7); R0(c, d, e, a, b, 8); R0(b, c, d, e, a, 9); R0(a, b, c, d, e, 10); R0(e, a, b, c, d, 11); R0(d, e, a, b, c, 12); R0(c, d, e, a, b, 13); R0(b, c, d, e, a, 14); R0(a, b, c, d, e, 15); R1(e, a, b, c, d, 16); R1(d, e, a, b, c, 17); R1(c, d, e, a, b, 18); R1(b, c, d, e, a, 19); R2(a, b, c, d, e, 20); R2(e, a, b, c, d, 21); R2(d, e, a, b, c, 22); R2(c, d, e, a, b, 23); R2(b, c, d, e, a, 24); R2(a, b, c, d, e, 25); R2(e, a, b, c, d, 26); R2(d, e, a, b, c, 27); R2(c, d, e, a, b, 28); R2(b, c, d, e, a, 29); R2(a, b, c, d, e, 30); R2(e, a, b, c, d, 31); R2(d, e, a, b, c, 32); R2(c, d, e, a, b, 33); R2(b, c, d, e, a, 34); R2(a, b, c, d, e, 35); R2(e, a, b, c, d, 36); R2(d, e, a, b, c, 37); R2(c, d, e, a, b, 38); R2(b, c, d, e, a, 39); R3(a, b, c, d, e, 40); R3(e, a, b, c, d, 41); R3(d, e, a, b, c, 42); R3(c, d, e, a, b, 43); R3(b, c, d, e, a, 44); R3(a, b, c, d, e, 45); R3(e, a, b, c, d, 46); R3(d, e, a, b, c, 47); R3(c, d, e, a, b, 48); R3(b, c, d, e, a, 49); R3(a, b, c, d, e, 50); R3(e, a, b, c, d, 51); R3(d, e, a, b, c, 52); R3(c, d, e, a, b, 53); R3(b, c, d, e, a, 54); R3(a, b, c, d, e, 55); R3(e, a, b, c, d, 56); R3(d, e, a, b, c, 57); R3(c, d, e, a, b, 58); R3(b, c, d, e, a, 59); R4(a, b, c, d, e, 60); R4(e, a, b, c, d, 61); R4(d, e, a, b, c, 62); R4(c, d, e, a, b, 63); R4(b, c, d, e, a, 64); R4(a, b, c, d, e, 65); R4(e, a, b, c, d, 66); R4(d, e, a, b, c, 67); R4(c, d, e, a, b, 68); R4(b, c, d, e, a, 69); R4(a, b, c, d, e, 70); R4(e, a, b, c, d, 71); R4(d, e, a, b, c, 72); R4(c, d, e, a, b, 73); R4(b, c, d, e, a, 74); R4(a, b, c, d, e, 75); R4(e, a, b, c, d, 76); R4(d, e, a, b, c, 77); R4(c, d, e, a, b, 78); R4(b, c, d, e, a, 79); // Add the working vars back into context.state[]. state[0] += a; state[1] += b; state[2] += c; state[3] += d; state[4] += e; } void SHA1::update(const std::string& src) { const uint8_t* buff = reinterpret_cast(src.data()); update(buff, src.size()); } // Run your data through this. void SHA1::update(const uint8_t* data, size_t input_len) { size_t i = 0; // Compute number of bytes mod 64. size_t index = (context_.count[0] >> 3) & 63; // Update number of bits. // TODO(xxx): Use uint64 instead of 2 uint32_t for count. // count[0] has low 29 bits for byte count + 3 pad 0's making 32 bits for // bit count. // Add bit count to low uint32_t context_.count[0] += static_cast(input_len << 3); if (context_.count[0] < static_cast(input_len << 3)) { ++context_.count[1]; // if overlow (carry), add one to high word } context_.count[1] += static_cast(input_len >> 29); if ((index + input_len) > 63) { i = 64 - index; memcpy(&context_.buffer[index], data, i); sha1Transform(context_.state, context_.buffer); for (; i + 63 < input_len; i += 64) { sha1Transform(context_.state, data + i); } index = 0; } memcpy(&context_.buffer[index], &data[i], input_len - i); } // Add padding and return the message digest. void SHA1::finalInternal() { uint8_t finalcount[8]; for (int i = 0; i < 8; ++i) { // Endian independent finalcount[i] = static_cast((context_.count[(i >= 4 ? 0 : 1)] >> ((3 - (i & 3)) * 8)) & 255); } update(reinterpret_cast("\200"), 1); while ((context_.count[0] & 504) != 448) { update(reinterpret_cast("\0"), 1); } // Should cause a SHA1Transform(). update(finalcount, 8); // Wipe variables. memset(finalcount, 0, 8); // SWR } void SHA1::final(void* digest) { char* data = static_cast(digest); finalInternal(); for (int i = 0; i < kSHA1DigestSize; ++i) { data[i] = static_cast((context_.state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255); } } static std::string encodeAsString(const void* data, size_t size, bool uppercase = false) { const char* hex_digits = uppercase ? "0123456789ABCDEF" : "0123456789abcdef"; const unsigned char* p = static_cast(data); const unsigned char *first = p; const unsigned char *end = p + size; std::string str; while (first != end) { unsigned char ch = *first; str.push_back(hex_digits[ch >> 4]); str.push_back(hex_digits[ch & 0x0F]); ++first; } return str; } std::string SHA1::hexFinal() { uint8_t digest[20]; final(&digest); return encodeAsString(digest, 20); } std::string SHA1::hexDigest(const std::string& src) { SHA1 sha1; sha1.update(src); return sha1.hexFinal(); } } }