From 94d557e93368624bad52722bb4c093d4ac5cc1b9 Mon Sep 17 00:00:00 2001 From: "wtc@chromium.org" Date: Wed, 23 Jun 2010 21:41:40 +0000 Subject: Implement the SecureHashAlgorithm class using Windows CryptoAPI. sha1.cc is renamed sha1_portable.cc. Change the swapends function to take a pointer instead of a non-const reference parameter. R=jhawkins,davidben,eroman BUG=47218 TEST=SHA1Test.* in base_unittests should pass. Review URL: http://codereview.chromium.org/2849018 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@50648 0039d316-1c4b-4281-b951-d872f2087c98 --- base/base.gypi | 4 +- base/sha1.cc | 202 -------------------------------------------------- base/sha1_portable.cc | 201 +++++++++++++++++++++++++++++++++++++++++++++++++ base/sha1_win.cc | 115 ++++++++++++++++++++++++++++ 4 files changed, 319 insertions(+), 203 deletions(-) delete mode 100644 base/sha1.cc create mode 100644 base/sha1_portable.cc create mode 100644 base/sha1_win.cc (limited to 'base') diff --git a/base/base.gypi b/base/base.gypi index 807181a..53d097e 100644 --- a/base/base.gypi +++ b/base/base.gypi @@ -200,8 +200,9 @@ 'scoped_variant_win.cc', 'scoped_variant_win.h', 'scoped_vector.h', - 'sha1.cc', 'sha1.h', + 'sha1_portable.cc', + 'sha1_win.cc', 'shared_memory.h', 'shared_memory_posix.cc', 'shared_memory_win.cc', @@ -348,6 +349,7 @@ 'event_recorder_stubs.cc', 'file_descriptor_shuffle.cc', 'message_pump_libevent.cc', + 'sha1_portable.cc', 'string16.cc', 'trace_event.cc', ], diff --git a/base/sha1.cc b/base/sha1.cc deleted file mode 100644 index 620dd56..0000000 --- a/base/sha1.cc +++ /dev/null @@ -1,202 +0,0 @@ -// 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(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(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(sha.Digest()), - SecureHashAlgorithm::kDigestSizeBytes); - return out; -} - -} // namespace base diff --git a/base/sha1_portable.cc b/base/sha1_portable.cc new file mode 100644 index 0000000..d0f3c1c --- /dev/null +++ b/base/sha1_portable.cc @@ -0,0 +1,201 @@ +// Copyright (c) 2010 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. + +// 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. See +// http://crbug.com/47218 + +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(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(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(sha.Digest()), + SecureHashAlgorithm::kDigestSizeBytes); + return out; +} + +} // namespace base diff --git a/base/sha1_win.cc b/base/sha1_win.cc new file mode 100644 index 0000000..b79ac38 --- /dev/null +++ b/base/sha1_win.cc @@ -0,0 +1,115 @@ +// Copyright (c) 2010 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 +#include + +#include "base/logging.h" +#include "base/string_util.h" + +namespace base { + +// Implementation of SHA-1 using Windows CryptoAPI. + +// 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(); + +class SecureHashAlgorithm { + public: + SecureHashAlgorithm() : prov_(NULL), hash_(NULL) { Init(); } + + 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(result_.data()); + } + + private: + // Cleans up prov_, hash_, and result_. + void Cleanup(); + + HCRYPTPROV prov_; + HCRYPTHASH hash_; + std::string result_; +}; + +void SecureHashAlgorithm::Init() { + Cleanup(); + + if (!CryptAcquireContext(&prov_, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { + LOG(ERROR) << "CryptAcquireContext failed: " << GetLastError(); + return; + } + + // Initialize the hash. + if (!CryptCreateHash(prov_, CALG_SHA1, 0, 0, &hash_)) { + LOG(ERROR) << "CryptCreateHash failed: " << GetLastError(); + return; + } +} + +void SecureHashAlgorithm::Update(const void* data, size_t nbytes) { + BOOL ok = CryptHashData(hash_, reinterpret_cast(data), + static_cast(nbytes), 0); + CHECK(ok) << "CryptHashData failed: " << GetLastError(); +} + +void SecureHashAlgorithm::Final() { + DWORD hash_len = 0; + DWORD buffer_size = sizeof(hash_len); + if (!CryptGetHashParam(hash_, HP_HASHSIZE, + reinterpret_cast(&hash_len), + &buffer_size, 0)) { + LOG(ERROR) << "CryptGetHashParam(HP_HASHSIZE) failed: " << GetLastError(); + result_.assign(SHA1_LENGTH, '\0'); + return; + } + + // Get the hash data. + if (!CryptGetHashParam(hash_, HP_HASHVAL, + reinterpret_cast(WriteInto(&result_, + hash_len + 1)), + &hash_len, 0)) { + LOG(ERROR) << "CryptGetHashParam(HP_HASHVAL) failed: " << GetLastError(); + result_.assign(SHA1_LENGTH, '\0'); + return; + } +} + +void SecureHashAlgorithm::Cleanup() { + BOOL ok; + if (hash_) { + ok = CryptDestroyHash(hash_); + DCHECK(ok); + hash_ = NULL; + } + if (prov_) { + ok = CryptReleaseContext(prov_, 0); + DCHECK(ok); + prov_ = NULL; + } + result_.clear(); +} + +std::string SHA1HashString(const std::string& str) { + SecureHashAlgorithm sha; + sha.Update(str.c_str(), str.length()); + sha.Final(); + std::string out(reinterpret_cast(sha.Digest()), SHA1_LENGTH); + return out; +} + +} // namespace base -- cgit v1.1