HMAC-SHA1 implementation for Mac based on CommonCrypto;
allow Windows HMAC-SHA1 to use keys longer than 16 bytes. Review URL: http://codereview.chromium.org/218 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@1724 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
base
chrome/browser/safe_browsing
@ -80,7 +80,7 @@ if env['PLATFORM'] == 'win32':
|
||||
'clipboard_util.cc',
|
||||
'event_recorder.cc',
|
||||
'file_version_info.cc',
|
||||
'hmac.cc', # Depends on OpenSSL; Mac team will investigate.
|
||||
'hmac_win.cc',
|
||||
|
||||
# This group all depends on MessageLoop.
|
||||
'idle_timer.cc',
|
||||
|
@ -81,6 +81,8 @@
|
||||
7BAE30E70E6D93A300C3F750 /* simple_thread.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BAE30E20E6D939800C3F750 /* simple_thread.cc */; };
|
||||
7BAE38AC0E6EFDBA00C3F750 /* thread_local_posix.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BAE38A90E6EFD9900C3F750 /* thread_local_posix.cc */; };
|
||||
7BAE38AF0E6EFDC300C3F750 /* thread_local_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BAE38AB0E6EFD9900C3F750 /* thread_local_unittest.cc */; };
|
||||
7BAE392A0E6F4EEF00C3F750 /* hmac_mac.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BAE39220E6F4EEC00C3F750 /* hmac_mac.cc */; };
|
||||
7BAE392B0E6F4EF200C3F750 /* hmac_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BAE39240E6F4EEC00C3F750 /* hmac_unittest.cc */; };
|
||||
7BAF501C0E50B84200CA8A07 /* base_paths.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BAF501B0E50B84200CA8A07 /* base_paths.cc */; };
|
||||
7BAF50760E50B8F100CA8A07 /* file_version_info_mac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7BAF50740E50B8F100CA8A07 /* file_version_info_mac.mm */; };
|
||||
7BD8F4A10E65AA4600034DE9 /* process_util_posix.cc in Sources */ = {isa = PBXBuildFile; fileRef = 7BD8F49F0E65AA2400034DE9 /* process_util_posix.cc */; };
|
||||
@ -351,6 +353,9 @@
|
||||
7BAE38A90E6EFD9900C3F750 /* thread_local_posix.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = thread_local_posix.cc; sourceTree = "<group>"; };
|
||||
7BAE38AA0E6EFD9900C3F750 /* thread_local_storage_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = thread_local_storage_unittest.cc; sourceTree = "<group>"; };
|
||||
7BAE38AB0E6EFD9900C3F750 /* thread_local_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = thread_local_unittest.cc; sourceTree = "<group>"; };
|
||||
7BAE39220E6F4EEC00C3F750 /* hmac_mac.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = hmac_mac.cc; sourceTree = "<group>"; };
|
||||
7BAE39240E6F4EEC00C3F750 /* hmac_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = hmac_unittest.cc; sourceTree = "<group>"; };
|
||||
7BAE39BA0E6F576200C3F750 /* hmac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = hmac.h; sourceTree = "<group>"; };
|
||||
7BAF4F7B0E50A3BD00CA8A07 /* logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = logging.h; sourceTree = "<group>"; };
|
||||
7BAF501B0E50B84200CA8A07 /* base_paths.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = base_paths.cc; sourceTree = "<group>"; };
|
||||
7BAF50740E50B8F100CA8A07 /* file_version_info_mac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = file_version_info_mac.mm; sourceTree = "<group>"; };
|
||||
@ -768,6 +773,9 @@
|
||||
93611B160E5A875D00F9405D /* histogram.cc */,
|
||||
93611B170E5A875D00F9405D /* histogram.h */,
|
||||
93611B190E5A878400F9405D /* histogram_unittest.cc */,
|
||||
7BAE39BA0E6F576200C3F750 /* hmac.h */,
|
||||
7BAE39220E6F4EEC00C3F750 /* hmac_mac.cc */,
|
||||
7BAE39240E6F4EEC00C3F750 /* hmac_unittest.cc */,
|
||||
8254030F0D92D1E80006B936 /* iat_patch.cc */,
|
||||
825403100D92D1E80006B936 /* iat_patch.h */,
|
||||
825403110D92D1E80006B936 /* icu_util.cc */,
|
||||
@ -1210,6 +1218,7 @@
|
||||
A5A0268E0E4A2BDC00498DA9 /* file_util_posix.cc in Sources */,
|
||||
7BAF50760E50B8F100CA8A07 /* file_version_info_mac.mm in Sources */,
|
||||
93611B180E5A875D00F9405D /* histogram.cc in Sources */,
|
||||
7BAE392A0E6F4EEF00C3F750 /* hmac_mac.cc in Sources */,
|
||||
8216A5060E34DBDD00EE374C /* icu_util.cc in Sources */,
|
||||
ABF4B9AF0DC2BC6200A6E319 /* json_reader.cc in Sources */,
|
||||
ABF4B9B00DC2BC6500A6E319 /* json_writer.cc in Sources */,
|
||||
@ -1284,6 +1293,7 @@
|
||||
A5CE1D2B0E55F4D800AD0606 /* file_util_unittest.cc in Sources */,
|
||||
7B78D3910E54FE0100609465 /* file_version_info_unittest.cc in Sources */,
|
||||
93611B1A0E5A878400F9405D /* histogram_unittest.cc in Sources */,
|
||||
7BAE392B0E6F4EF200C3F750 /* hmac_unittest.cc in Sources */,
|
||||
AB956E0A0E5DDC0900BBE9D8 /* image_operations_unittest.cc in Sources */,
|
||||
7B78D3920E54FE0100609465 /* json_reader_unittest.cc in Sources */,
|
||||
7B78D3930E54FE0100609465 /* json_writer_unittest.cc in Sources */,
|
||||
|
@ -310,11 +310,11 @@
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\hmac.cc"
|
||||
RelativePath="..\hmac.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\hmac.h"
|
||||
RelativePath="..\hmac_win.cc"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
|
36
base/hmac.h
36
base/hmac.h
@ -1,20 +1,26 @@
|
||||
// Copyright (c) 2006-2008 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.
|
||||
//
|
||||
|
||||
// Utility class for calculating the HMAC for a given message. We currently
|
||||
// only support SHA1 for the hash algorithm, but this can be extended easily.
|
||||
|
||||
#ifndef BASE_HMAC_H__
|
||||
#define BASE_HMAC_H__
|
||||
#ifndef BASE_HMAC_H_
|
||||
#define BASE_HMAC_H_
|
||||
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include <windows.h>
|
||||
#include <wincrypt.h>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
class HMAC {
|
||||
public:
|
||||
// The set of supported hash functions. Extend as required.
|
||||
@ -25,16 +31,17 @@ class HMAC {
|
||||
HMAC(HashAlgorithm hash_alg, const unsigned char* key, int key_length);
|
||||
~HMAC();
|
||||
|
||||
// Returns the HMAC in 'digest' for the message in 'data' and the key
|
||||
// specified in the contructor.
|
||||
// Calculates the HMAC for the message in |data| using the algorithm and key
|
||||
// supplied to the constructor. The HMAC is returned in |digest|, which
|
||||
// has |digest_length| bytes of storage available.
|
||||
bool Sign(const std::string& data, unsigned char* digest, int digest_length);
|
||||
|
||||
private:
|
||||
#if defined(OS_POSIX)
|
||||
HashAlgorithm hash_alg_;
|
||||
std::string key_;
|
||||
#elif defined(OS_WIN)
|
||||
// Import the key so that we don't have to store it ourself.
|
||||
// TODO(paulg): Bug: http://b/1084719, 'ImportKey' will not currently work on
|
||||
// Windows 2000 since it requires special handling for importing
|
||||
// keys. See this link for details:
|
||||
// http://www.derkeiler.com/Newsgroups/microsoft.public.platformsdk.security/2004-06/0270.html
|
||||
void ImportKey(const unsigned char* key, int key_length);
|
||||
|
||||
// Returns the SHA1 hash of 'data' and 'key' in 'digest'. If there was any
|
||||
@ -43,10 +50,6 @@ class HMAC {
|
||||
unsigned char* digest,
|
||||
int digest_length);
|
||||
|
||||
// Required for the SHA1 key_blob struct. We limit this to 16 bytes since
|
||||
// Windows 2000 doesn't support keys larger than that.
|
||||
static const int kMaxKeySize = 16;
|
||||
|
||||
// The hash algorithm to use.
|
||||
HashAlgorithm hash_alg_;
|
||||
|
||||
@ -54,10 +57,11 @@ class HMAC {
|
||||
HCRYPTPROV provider_;
|
||||
HCRYPTHASH hash_;
|
||||
HCRYPTKEY hkey_;
|
||||
#endif // OS_WIN
|
||||
|
||||
DISALLOW_EVIL_CONSTRUCTORS(HMAC);
|
||||
DISALLOW_COPY_AND_ASSIGN(HMAC);
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_HMAC_H__
|
||||
|
||||
#endif // BASE_HMAC_H_
|
||||
|
52
base/hmac_mac.cc
Normal file
52
base/hmac_mac.cc
Normal file
@ -0,0 +1,52 @@
|
||||
// Copyright (c) 2008 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/hmac.h"
|
||||
|
||||
#include <CommonCrypto/CommonHMAC.h>
|
||||
|
||||
#include "base/logging.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
HMAC::HMAC(HashAlgorithm hash_alg, const unsigned char* key, int key_length)
|
||||
: hash_alg_(hash_alg),
|
||||
key_(reinterpret_cast<const char*>(key), key_length) {
|
||||
}
|
||||
|
||||
HMAC::~HMAC() {
|
||||
// Zero out key copy.
|
||||
key_.assign(key_.length(), std::string::value_type());
|
||||
key_.clear();
|
||||
key_.reserve(0);
|
||||
}
|
||||
|
||||
bool HMAC::Sign(const std::string& data,
|
||||
unsigned char* digest,
|
||||
int digest_length) {
|
||||
CCHmacAlgorithm algorithm;
|
||||
int algorithm_digest_length;
|
||||
switch (hash_alg_) {
|
||||
case SHA1:
|
||||
algorithm = kCCHmacAlgSHA1;
|
||||
algorithm_digest_length = CC_SHA1_DIGEST_LENGTH;
|
||||
break;
|
||||
default:
|
||||
NOTREACHED();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (digest_length < algorithm_digest_length) {
|
||||
NOTREACHED();
|
||||
return false;
|
||||
}
|
||||
|
||||
CCHmac(algorithm,
|
||||
key_.data(), key_.length(), data.data(), data.length(),
|
||||
digest);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace base
|
@ -7,21 +7,23 @@
|
||||
#include "base/hmac.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
static const int kKeySize = 16;
|
||||
static const int kDigestSize = 20;
|
||||
|
||||
// Client key.
|
||||
const unsigned char kClientKey[kKeySize] =
|
||||
{ 0xbf, 0xf6, 0x83, 0x4b, 0x3e, 0xa3, 0x23, 0xdd,
|
||||
0x96, 0x78, 0x70, 0x8e, 0xa1, 0x9d, 0x3b, 0x40 };
|
||||
TEST(HMACTest, HmacSafeBrowsingResponseTest) {
|
||||
const int kKeySize = 16;
|
||||
|
||||
// Expected HMAC result using kMessage and kClientKey.
|
||||
const unsigned char kReceivedHmac[kDigestSize] =
|
||||
{ 0xb9, 0x3c, 0xd6, 0xf0, 0x49, 0x47, 0xe2, 0x52,
|
||||
0x59, 0x7a, 0xbd, 0x1f, 0x2b, 0x4c, 0x83, 0xad,
|
||||
0x86, 0xd2, 0x48, 0x85 };
|
||||
// Client key.
|
||||
const unsigned char kClientKey[kKeySize] =
|
||||
{ 0xbf, 0xf6, 0x83, 0x4b, 0x3e, 0xa3, 0x23, 0xdd,
|
||||
0x96, 0x78, 0x70, 0x8e, 0xa1, 0x9d, 0x3b, 0x40 };
|
||||
|
||||
const char kMessage[] =
|
||||
// Expected HMAC result using kMessage and kClientKey.
|
||||
const unsigned char kReceivedHmac[kDigestSize] =
|
||||
{ 0xb9, 0x3c, 0xd6, 0xf0, 0x49, 0x47, 0xe2, 0x52,
|
||||
0x59, 0x7a, 0xbd, 0x1f, 0x2b, 0x4c, 0x83, 0xad,
|
||||
0x86, 0xd2, 0x48, 0x85 };
|
||||
|
||||
const char kMessage[] =
|
||||
"n:1896\ni:goog-malware-shavar\nu:s.ytimg.com/safebrowsing/rd/goog-malware-shav"
|
||||
"ar_s_445-450\nu:s.ytimg.com/safebrowsing/rd/goog-malware-shavar_s_439-444\nu:s"
|
||||
".ytimg.com/safebrowsing/rd/goog-malware-shavar_s_437\nu:s.ytimg.com/safebrowsi"
|
||||
@ -47,12 +49,115 @@ const char kMessage[] =
|
||||
"-phish-shavar_a_2629-2631\nu:s.ytimg.com/safebrowsing/rd/goog-phish-shavar_a_2"
|
||||
"626-2628\nu:s.ytimg.com/safebrowsing/rd/goog-phish-shavar_a_2625\n";
|
||||
|
||||
TEST(HMACTest, HmacSafeBrowsingResponseTest) {
|
||||
std::string message_data(kMessage);
|
||||
|
||||
HMAC hmac(HMAC::SHA1, kClientKey, kKeySize);
|
||||
base::HMAC hmac(base::HMAC::SHA1, kClientKey, kKeySize);
|
||||
unsigned char calculated_hmac[kDigestSize];
|
||||
|
||||
EXPECT_TRUE(hmac.Sign(message_data, calculated_hmac, kDigestSize));
|
||||
EXPECT_EQ(memcmp(kReceivedHmac, calculated_hmac, kDigestSize), 0);
|
||||
}
|
||||
|
||||
// Test cases from RFC 2202 section 3
|
||||
TEST(HMACTest, RFC2202TestCases) {
|
||||
const struct {
|
||||
const char *key;
|
||||
const int key_len;
|
||||
const char *data;
|
||||
const int data_len;
|
||||
const char *digest;
|
||||
} cases[] = {
|
||||
{ "\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B\x0B"
|
||||
"\x0B\x0B\x0B\x0B", 20,
|
||||
"Hi There", 8,
|
||||
"\xB6\x17\x31\x86\x55\x05\x72\x64\xE2\x8B\xC0\xB6\xFB\x37\x8C\x8E"
|
||||
"\xF1\x46\xBE\x00" },
|
||||
{ "Jefe", 4,
|
||||
"what do ya want for nothing?", 28,
|
||||
"\xEF\xFC\xDF\x6A\xE5\xEB\x2F\xA2\xD2\x74\x16\xD5\xF1\x84\xDF\x9C"
|
||||
"\x25\x9A\x7C\x79" },
|
||||
{ "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
|
||||
"\xAA\xAA\xAA\xAA", 20,
|
||||
"\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
|
||||
"\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
|
||||
"\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD"
|
||||
"\xDD\xDD", 50,
|
||||
"\x12\x5D\x73\x42\xB9\xAC\x11\xCD\x91\xA3\x9A\xF4\x8A\xA1\x7B\x4F"
|
||||
"\x63\xF1\x75\xD3" },
|
||||
{ "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10"
|
||||
"\x11\x12\x13\x14\x15\x16\x17\x18\x19", 25,
|
||||
"\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
|
||||
"\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
|
||||
"\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD\xCD"
|
||||
"\xCD\xCD", 50,
|
||||
"\x4C\x90\x07\xF4\x02\x62\x50\xC6\xBC\x84\x14\xF9\xBF\x50\xC8\x6C"
|
||||
"\x2D\x72\x35\xDA" },
|
||||
{ "\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C\x0C"
|
||||
"\x0C\x0C\x0C\x0C", 20,
|
||||
"Test With Truncation", 20,
|
||||
"\x4C\x1A\x03\x42\x4B\x55\xE0\x7F\xE7\xF2\x7B\xE1\xD5\x8B\xB9\x32"
|
||||
"\x4A\x9A\x5A\x04" },
|
||||
{ "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
|
||||
"\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
|
||||
"\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
|
||||
"\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
|
||||
"\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA",
|
||||
80,
|
||||
"Test Using Larger Than Block-Size Key - Hash Key First", 54,
|
||||
"\xAA\x4A\xE5\xE1\x52\x72\xD0\x0E\x95\x70\x56\x37\xCE\x8A\x3B\x55"
|
||||
"\xED\x40\x21\x12" },
|
||||
{ "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
|
||||
"\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
|
||||
"\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
|
||||
"\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
|
||||
"\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA",
|
||||
80,
|
||||
"Test Using Larger Than Block-Size Key and Larger "
|
||||
"Than One Block-Size Data", 73,
|
||||
"\xE8\xE9\x9D\x0F\x45\x23\x7D\x78\x6D\x6B\xBA\xA7\x96\x5C\x78\x08"
|
||||
"\xBB\xFF\x1A\x91" }
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
|
||||
base::HMAC hmac(base::HMAC::SHA1,
|
||||
reinterpret_cast<const unsigned char*>(cases[i].key),
|
||||
cases[i].key_len);
|
||||
std::string data_string(cases[i].data, cases[i].data_len);
|
||||
unsigned char digest[kDigestSize];
|
||||
EXPECT_TRUE(hmac.Sign(data_string, digest, kDigestSize));
|
||||
EXPECT_EQ(memcmp(cases[i].digest, digest, kDigestSize), 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(HMACTest, HMACObjectReuse) {
|
||||
const char *key =
|
||||
"\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
|
||||
"\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
|
||||
"\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
|
||||
"\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA"
|
||||
"\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA";
|
||||
const int key_len = 80;
|
||||
|
||||
const struct {
|
||||
const char *data;
|
||||
const int data_len;
|
||||
const char *digest;
|
||||
} cases[] = {
|
||||
{ "Test Using Larger Than Block-Size Key - Hash Key First", 54,
|
||||
"\xAA\x4A\xE5\xE1\x52\x72\xD0\x0E\x95\x70\x56\x37\xCE\x8A\x3B\x55"
|
||||
"\xED\x40\x21\x12" },
|
||||
{ "Test Using Larger Than Block-Size Key and Larger "
|
||||
"Than One Block-Size Data", 73,
|
||||
"\xE8\xE9\x9D\x0F\x45\x23\x7D\x78\x6D\x6B\xBA\xA7\x96\x5C\x78\x08"
|
||||
"\xBB\xFF\x1A\x91" }
|
||||
};
|
||||
|
||||
base::HMAC hmac(base::HMAC::SHA1,
|
||||
reinterpret_cast<const unsigned char*>(key), key_len);
|
||||
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
|
||||
std::string data_string(cases[i].data, cases[i].data_len);
|
||||
unsigned char digest[kDigestSize];
|
||||
EXPECT_TRUE(hmac.Sign(data_string, digest, kDigestSize));
|
||||
EXPECT_EQ(memcmp(cases[i].digest, digest, kDigestSize), 0);
|
||||
}
|
||||
}
|
||||
|
@ -3,8 +3,14 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "base/hmac.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include "base/logging.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
HMAC::HMAC(HashAlgorithm hash_alg, const unsigned char* key, int key_length)
|
||||
: hash_alg_(hash_alg),
|
||||
provider_(NULL),
|
||||
@ -41,30 +47,36 @@ bool HMAC::Sign(const std::string& data,
|
||||
}
|
||||
|
||||
void HMAC::ImportKey(const unsigned char* key, int key_length) {
|
||||
if (key_length > kMaxKeySize) {
|
||||
NOTREACHED();
|
||||
return;
|
||||
}
|
||||
// This code doesn't work on Win2k because PLAINTEXTKEYBLOB and
|
||||
// CRYPT_IPSEC_HMAC_KEY are not supported on Windows 2000. PLAINTEXTKEYBLOB
|
||||
// allows the import of an unencrypted key. For Win2k support, a cubmbersome
|
||||
// exponent-of-one key procedure must be used:
|
||||
// http://support.microsoft.com/kb/228786/en-us
|
||||
// CRYPT_IPSEC_HMAC_KEY allows keys longer than 16 bytes.
|
||||
|
||||
struct {
|
||||
struct KeyBlob {
|
||||
BLOBHEADER header;
|
||||
DWORD key_size;
|
||||
BYTE key_data[kMaxKeySize];
|
||||
} key_blob;
|
||||
key_blob.header.bType = PLAINTEXTKEYBLOB;
|
||||
key_blob.header.bVersion = CUR_BLOB_VERSION;
|
||||
key_blob.header.reserved = 0;
|
||||
key_blob.header.aiKeyAlg = CALG_RC2;
|
||||
key_blob.key_size = key_length;
|
||||
memcpy(key_blob.key_data, key, key_length);
|
||||
BYTE key_data[1];
|
||||
};
|
||||
size_t key_blob_size = std::max(offsetof(KeyBlob, key_data) + key_length,
|
||||
sizeof(KeyBlob));
|
||||
std::vector<BYTE> key_blob_storage = std::vector<BYTE>(key_blob_size);
|
||||
KeyBlob* key_blob = reinterpret_cast<KeyBlob*>(&key_blob_storage[0]);
|
||||
key_blob->header.bType = PLAINTEXTKEYBLOB;
|
||||
key_blob->header.bVersion = CUR_BLOB_VERSION;
|
||||
key_blob->header.reserved = 0;
|
||||
key_blob->header.aiKeyAlg = CALG_RC2;
|
||||
key_blob->key_size = key_length;
|
||||
memcpy(key_blob->key_data, key, key_length);
|
||||
|
||||
if (!CryptImportKey(provider_,
|
||||
reinterpret_cast<const BYTE *>(&key_blob),
|
||||
sizeof(key_blob), 0, 0, &hkey_))
|
||||
if (!CryptImportKey(provider_, &key_blob_storage[0], key_blob_storage.size(),
|
||||
0, CRYPT_IPSEC_HMAC_KEY, &hkey_)) {
|
||||
hkey_ = NULL;
|
||||
}
|
||||
|
||||
// Destroy the copy of the key.
|
||||
SecureZeroMemory(key_blob.key_data, key_length);
|
||||
SecureZeroMemory(key_blob->key_data, key_length);
|
||||
}
|
||||
|
||||
bool HMAC::SignWithSHA1(const std::string& data,
|
||||
@ -95,3 +107,4 @@ bool HMAC::SignWithSHA1(const std::string& data,
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace base
|
@ -147,9 +147,9 @@ bool VerifyMAC(const std::string& key, const std::string& mac,
|
||||
std::string decoded_mac;
|
||||
net::Base64Decode(mac_copy, &decoded_mac);
|
||||
|
||||
HMAC hmac(HMAC::SHA1,
|
||||
reinterpret_cast<const unsigned char*>(decoded_key.data()),
|
||||
static_cast<int>(decoded_key.length()));
|
||||
base::HMAC hmac(base::HMAC::SHA1,
|
||||
reinterpret_cast<const unsigned char*>(decoded_key.data()),
|
||||
static_cast<int>(decoded_key.length()));
|
||||
const std::string data_str(data, data_length);
|
||||
unsigned char digest[kSafeBrowsingMacDigestSize];
|
||||
if (!hmac.Sign(data_str, digest, kSafeBrowsingMacDigestSize))
|
||||
|
Reference in New Issue
Block a user