1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Use of this source code is governed by a BSD-style license that can be 3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// found in the LICENSE file. 4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 5ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "crypto/hmac.h" 6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <windows.h> 8c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <wincrypt.h> 9c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 10c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <algorithm> 11c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include <vector> 12c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 13c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/logging.h" 14ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "crypto/scoped_capi_types.h" 15ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "crypto/third_party/nss/blapi.h" 16ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "crypto/third_party/nss/sha256.h" 17c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 18ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsennamespace crypto { 19c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace { 21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Implementation of HMAC-SHA-256: 23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// 24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// SHA-256 is supported in Windows XP SP3 or later. We still need to support 25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Windows XP SP2, so unfortunately we have to implement HMAC-SHA-256 here. 26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochenum { 28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SHA256_BLOCK_SIZE = 64 // Block size (in bytes) of the input to SHA-256. 29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}; 30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// See FIPS 198: The Keyed-Hash Message Authentication Code (HMAC). 32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ComputeHMACSHA256(const unsigned char* key, size_t key_len, 33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const unsigned char* text, size_t text_len, 34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch unsigned char* output, size_t output_len) { 35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SHA256Context ctx; 36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Pre-process the key, if necessary. 38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch unsigned char key0[SHA256_BLOCK_SIZE]; 39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (key_len > SHA256_BLOCK_SIZE) { 40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SHA256_Begin(&ctx); 41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SHA256_Update(&ctx, key, key_len); 42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SHA256_End(&ctx, key0, NULL, SHA256_LENGTH); 43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch memset(key0 + SHA256_LENGTH, 0, SHA256_BLOCK_SIZE - SHA256_LENGTH); 44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch memcpy(key0, key, key_len); 46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch memset(key0 + key_len, 0, SHA256_BLOCK_SIZE - key_len); 47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch unsigned char padded_key[SHA256_BLOCK_SIZE]; 50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch unsigned char inner_hash[SHA256_LENGTH]; 51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // XOR key0 with ipad. 53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (int i = 0; i < SHA256_BLOCK_SIZE; ++i) 54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch padded_key[i] = key0[i] ^ 0x36; 55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Compute the inner hash. 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SHA256_Begin(&ctx); 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SHA256_Update(&ctx, padded_key, SHA256_BLOCK_SIZE); 59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SHA256_Update(&ctx, text, text_len); 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SHA256_End(&ctx, inner_hash, NULL, SHA256_LENGTH); 61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // XOR key0 with opad. 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (int i = 0; i < SHA256_BLOCK_SIZE; ++i) 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch padded_key[i] = key0[i] ^ 0x5c; 65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Compute the outer hash. 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SHA256_Begin(&ctx); 68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SHA256_Update(&ctx, padded_key, SHA256_BLOCK_SIZE); 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SHA256_Update(&ctx, inner_hash, SHA256_LENGTH); 70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch SHA256_End(&ctx, output, NULL, output_len); 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} // namespace 74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 75c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottstruct HMACPlatformData { 76731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick ~HMACPlatformData() { 77731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (!raw_key_.empty()) { 78731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick SecureZeroMemory(&raw_key_[0], raw_key_.size()); 79731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } 80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 81731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick // Destroy the key before releasing the provider. 82731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick key_.reset(); 83731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick } 84731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick 85731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick ScopedHCRYPTPROV provider_; 86731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick ScopedHCRYPTKEY key_; 87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // For HMAC-SHA-256 only. 89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch std::vector<unsigned char> raw_key_; 90c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}; 91c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 92c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottHMAC::HMAC(HashAlgorithm hash_alg) 93c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott : hash_alg_(hash_alg), plat_(new HMACPlatformData()) { 94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Only SHA-1 and SHA-256 hash algorithms are supported now. 95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(hash_alg_ == SHA1 || hash_alg_ == SHA256); 96c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 97c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 98731df977c0511bca2206b5f333555b1205ff1f43Iain Merrickbool HMAC::Init(const unsigned char* key, int key_length) { 99731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (plat_->provider_ || plat_->key_ || !plat_->raw_key_.empty()) { 100c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Init must not be called more than once on the same HMAC object. 101c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott NOTREACHED(); 102c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 103c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 104c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (hash_alg_ == SHA256) { 106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (key_length < SHA256_LENGTH / 2) 107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; // Key is too short. 108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch plat_->raw_key_.assign(key, key + key_length); 109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 112731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (!CryptAcquireContext(plat_->provider_.receive(), NULL, NULL, 113c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { 114c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott NOTREACHED(); 115c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 116c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 117c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 118c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // This code doesn't work on Win2k because PLAINTEXTKEYBLOB and 119c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // CRYPT_IPSEC_HMAC_KEY are not supported on Windows 2000. PLAINTEXTKEYBLOB 120c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // allows the import of an unencrypted key. For Win2k support, a cubmbersome 121c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // exponent-of-one key procedure must be used: 122c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // http://support.microsoft.com/kb/228786/en-us 123c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // CRYPT_IPSEC_HMAC_KEY allows keys longer than 16 bytes. 124c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 125c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott struct KeyBlob { 126c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott BLOBHEADER header; 127c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DWORD key_size; 128c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott BYTE key_data[1]; 129c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott }; 130c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott size_t key_blob_size = std::max(offsetof(KeyBlob, key_data) + key_length, 131c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott sizeof(KeyBlob)); 132c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott std::vector<BYTE> key_blob_storage = std::vector<BYTE>(key_blob_size); 133c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott KeyBlob* key_blob = reinterpret_cast<KeyBlob*>(&key_blob_storage[0]); 134c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott key_blob->header.bType = PLAINTEXTKEYBLOB; 135c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott key_blob->header.bVersion = CUR_BLOB_VERSION; 136c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott key_blob->header.reserved = 0; 137c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott key_blob->header.aiKeyAlg = CALG_RC2; 138c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott key_blob->key_size = key_length; 139c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott memcpy(key_blob->key_data, key, key_length); 140c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 141c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!CryptImportKey(plat_->provider_, &key_blob_storage[0], 142c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott key_blob_storage.size(), 0, CRYPT_IPSEC_HMAC_KEY, 143731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick plat_->key_.receive())) { 144c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott NOTREACHED(); 145c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 146c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 147c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 148c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Destroy the copy of the key. 149c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SecureZeroMemory(key_blob->key_data, key_length); 150c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 151c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return true; 152c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 153c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 154c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick ScottHMAC::~HMAC() { 155c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 156c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 157c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottbool HMAC::Sign(const std::string& data, 158c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott unsigned char* digest, 159c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott int digest_length) { 160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (hash_alg_ == SHA256) { 161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (plat_->raw_key_.empty()) 162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return false; 163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ComputeHMACSHA256(&plat_->raw_key_[0], plat_->raw_key_.size(), 164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch reinterpret_cast<const unsigned char*>(data.data()), 165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch data.size(), digest, digest_length); 166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return true; 167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 169731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (!plat_->provider_ || !plat_->key_) 170c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 171c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 172c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (hash_alg_ != SHA1) { 173c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott NOTREACHED(); 174c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 175c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 176c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 177731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick ScopedHCRYPTHASH hash; 178731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (!CryptCreateHash(plat_->provider_, CALG_HMAC, plat_->key_, 0, 179731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick hash.receive())) 180c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 181c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 182c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott HMAC_INFO hmac_info; 183c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott memset(&hmac_info, 0, sizeof(hmac_info)); 184c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott hmac_info.HashAlgid = CALG_SHA1; 185731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (!CryptSetHashParam(hash, HP_HMAC_INFO, 186c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott reinterpret_cast<BYTE*>(&hmac_info), 0)) 187c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 188c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 189731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick if (!CryptHashData(hash, reinterpret_cast<const BYTE*>(data.data()), 190c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott static_cast<DWORD>(data.size()), 0)) 191c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return false; 192c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 193c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DWORD sha1_size = digest_length; 194731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick return !!CryptGetHashParam(hash, HP_HASHVAL, digest, &sha1_size, 0); 195c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} 196c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 197ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen} // namespace crypto 198