// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/sha1.h" #include "base/basictypes.h" namespace base { // Implementation of SHA-1. Only handles data in byte-sized blocks, // which simplifies the code a fair bit. // This file also contains an HMAC implementation using SHA-1 // Identifier names follow notation in FIPS PUB 180-3, where you'll // also find a description of the algorithm: // http://csrc.nist.gov/publications/fips/fips180-3/fips180-3_final.pdf // Usage example: // // SecureHashAlgorithm sha; // while(there is data to hash) // sha.Update(moredata, size of data); // sha.Final(); // memcpy(somewhere, sha.Digest(), 20); // // to reuse the instance of sha, call sha.Init(); // TODO(jhawkins): Replace this implementation with a per-platform // implementation using each platform's crypto library. class SecureHashAlgorithm { public: SecureHashAlgorithm() { Init(); } static const int kDigestSizeBytes; void Init(); void Update(const void* data, size_t nbytes); void Final(); // 20 bytes of message digest. const unsigned char* Digest() const { return reinterpret_cast<const unsigned char*>(H); } private: void Pad(); void Process(); uint32 A, B, C, D, E; uint32 H[5]; union { uint32 W[80]; uint8 M[64]; }; uint32 cursor; uint32 l; }; static inline uint32 f(uint32 t, uint32 B, uint32 C, uint32 D) { if (t < 20) { return (B & C) | ((~B) & D); } else if (t < 40) { return B ^ C ^ D; } else if (t < 60) { return (B & C) | (B & D) | (C & D); } else { return B ^ C ^ D; } } static inline uint32 S(uint32 n, uint32 X) { return (X << n) | (X >> (32-n)); } static inline uint32 K(uint32 t) { if (t < 20) { return 0x5a827999; } else if (t < 40) { return 0x6ed9eba1; } else if (t < 60) { return 0x8f1bbcdc; } else { return 0xca62c1d6; } } static inline void swapends(uint32& t) { t = ((t & 0xff000000) >> 24) | ((t & 0xff0000) >> 8) | ((t & 0xff00) << 8) | ((t & 0xff) << 24); } const int SecureHashAlgorithm::kDigestSizeBytes = 20; void SecureHashAlgorithm::Init() { cursor = 0; l = 0; H[0] = 0x67452301; H[1] = 0xefcdab89; H[2] = 0x98badcfe; H[3] = 0x10325476; H[4] = 0xc3d2e1f0; } void SecureHashAlgorithm::Final() { Pad(); Process(); for (int t = 0; t < 5; ++t) swapends(H[t]); } void SecureHashAlgorithm::Update(const void* data, size_t nbytes) { const uint8* d = reinterpret_cast<const uint8*>(data); while (nbytes--) { M[cursor++] = *d++; if (cursor >= 64) Process(); l += 8; } } void SecureHashAlgorithm::Pad() { M[cursor++] = 0x80; if (cursor > 64-8) { // pad out to next block while (cursor < 64) M[cursor++] = 0; Process(); } while (cursor < 64-4) M[cursor++] = 0; M[64-4] = (l & 0xff000000) >> 24; M[64-3] = (l & 0xff0000) >> 16; M[64-2] = (l & 0xff00) >> 8; M[64-1] = (l & 0xff); } void SecureHashAlgorithm::Process() { uint32 t; // Each a...e corresponds to a section in the FIPS 180-3 algorithm. // a. // // W and M are in a union, so no need to memcpy. // memcpy(W, M, sizeof(M)); for (t = 0; t < 16; ++t) swapends(W[t]); // b. for (t = 16; t < 80; ++t) W[t] = S(1, W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]); // c. A = H[0]; B = H[1]; C = H[2]; D = H[3]; E = H[4]; // d. for (t = 0; t < 80; ++t) { uint32 TEMP = S(5, A) + f(t, B, C, D) + E + W[t] + K(t); E = D; D = C; C = S(30, B); B = A; A = TEMP; } // e. H[0] += A; H[1] += B; H[2] += C; H[3] += D; H[4] += E; cursor = 0; } std::string SHA1HashString(const std::string& str) { SecureHashAlgorithm sha; sha.Update(str.c_str(), str.length()); sha.Final(); std::string out(reinterpret_cast<const char*>(sha.Digest()), SecureHashAlgorithm::kDigestSizeBytes); return out; } } // namespace base