1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/hmac.h" 6 7 #include <windows.h> 8 #include <wincrypt.h> 9 10 #include <algorithm> 11 #include <vector> 12 13 #include "base/logging.h" 14 15 namespace base { 16 17 struct HMACPlatformData { 18 // Windows Crypt API resources. 19 HCRYPTPROV provider_; 20 HCRYPTHASH hash_; 21 HCRYPTKEY hkey_; 22 }; 23 24 HMAC::HMAC(HashAlgorithm hash_alg) 25 : hash_alg_(hash_alg), plat_(new HMACPlatformData()) { 26 // Only SHA-1 digest is supported now. 27 DCHECK(hash_alg_ == SHA1); 28 } 29 30 bool HMAC::Init(const unsigned char *key, int key_length) { 31 if (plat_->provider_ || plat_->hkey_) { 32 // Init must not be called more than once on the same HMAC object. 33 NOTREACHED(); 34 return false; 35 } 36 37 if (!CryptAcquireContext(&plat_->provider_, NULL, NULL, 38 PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { 39 NOTREACHED(); 40 plat_->provider_ = NULL; 41 return false; 42 } 43 44 // This code doesn't work on Win2k because PLAINTEXTKEYBLOB and 45 // CRYPT_IPSEC_HMAC_KEY are not supported on Windows 2000. PLAINTEXTKEYBLOB 46 // allows the import of an unencrypted key. For Win2k support, a cubmbersome 47 // exponent-of-one key procedure must be used: 48 // http://support.microsoft.com/kb/228786/en-us 49 // CRYPT_IPSEC_HMAC_KEY allows keys longer than 16 bytes. 50 51 struct KeyBlob { 52 BLOBHEADER header; 53 DWORD key_size; 54 BYTE key_data[1]; 55 }; 56 size_t key_blob_size = std::max(offsetof(KeyBlob, key_data) + key_length, 57 sizeof(KeyBlob)); 58 std::vector<BYTE> key_blob_storage = std::vector<BYTE>(key_blob_size); 59 KeyBlob* key_blob = reinterpret_cast<KeyBlob*>(&key_blob_storage[0]); 60 key_blob->header.bType = PLAINTEXTKEYBLOB; 61 key_blob->header.bVersion = CUR_BLOB_VERSION; 62 key_blob->header.reserved = 0; 63 key_blob->header.aiKeyAlg = CALG_RC2; 64 key_blob->key_size = key_length; 65 memcpy(key_blob->key_data, key, key_length); 66 67 if (!CryptImportKey(plat_->provider_, &key_blob_storage[0], 68 key_blob_storage.size(), 0, CRYPT_IPSEC_HMAC_KEY, 69 &plat_->hkey_)) { 70 NOTREACHED(); 71 plat_->hkey_ = NULL; 72 return false; 73 } 74 75 // Destroy the copy of the key. 76 SecureZeroMemory(key_blob->key_data, key_length); 77 78 return true; 79 } 80 81 HMAC::~HMAC() { 82 BOOL ok; 83 if (plat_->hkey_) { 84 ok = CryptDestroyKey(plat_->hkey_); 85 DCHECK(ok); 86 } 87 if (plat_->hash_) { 88 ok = CryptDestroyHash(plat_->hash_); 89 DCHECK(ok); 90 } 91 if (plat_->provider_) { 92 ok = CryptReleaseContext(plat_->provider_, 0); 93 DCHECK(ok); 94 } 95 } 96 97 bool HMAC::Sign(const std::string& data, 98 unsigned char* digest, 99 int digest_length) { 100 if (!plat_->provider_ || !plat_->hkey_) 101 return false; 102 103 if (hash_alg_ != SHA1) { 104 NOTREACHED(); 105 return false; 106 } 107 108 if (!CryptCreateHash( 109 plat_->provider_, CALG_HMAC, plat_->hkey_, 0, &plat_->hash_)) 110 return false; 111 112 HMAC_INFO hmac_info; 113 memset(&hmac_info, 0, sizeof(hmac_info)); 114 hmac_info.HashAlgid = CALG_SHA1; 115 if (!CryptSetHashParam(plat_->hash_, HP_HMAC_INFO, 116 reinterpret_cast<BYTE*>(&hmac_info), 0)) 117 return false; 118 119 if (!CryptHashData(plat_->hash_, 120 reinterpret_cast<const BYTE*>(data.data()), 121 static_cast<DWORD>(data.size()), 0)) 122 return false; 123 124 DWORD sha1_size = digest_length; 125 if (!CryptGetHashParam(plat_->hash_, HP_HASHVAL, digest, &sha1_size, 0)) 126 return false; 127 128 return true; 129 } 130 131 } // namespace base 132