1 // Copyright (c) 2011 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.
5 #include "crypto/hmac.h"
13 #include "base/logging.h"
14 #include "crypto/scoped_capi_types.h"
15 #include "crypto/third_party/nss/blapi.h"
16 #include "crypto/third_party/nss/sha256.h"
22 // Implementation of HMAC-SHA-256:
24 // SHA-256 is supported in Windows XP SP3 or later. We still need to support
25 // Windows XP SP2, so unfortunately we have to implement HMAC-SHA-256 here.
28 SHA256_BLOCK_SIZE
= 64 // Block size (in bytes) of the input to SHA-256.
31 // See FIPS 198: The Keyed-Hash Message Authentication Code (HMAC).
32 void ComputeHMACSHA256(const unsigned char* key
, size_t key_len
,
33 const unsigned char* text
, size_t text_len
,
34 unsigned char* output
, size_t output_len
) {
37 // Pre-process the key, if necessary.
38 unsigned char key0
[SHA256_BLOCK_SIZE
];
39 if (key_len
> SHA256_BLOCK_SIZE
) {
41 SHA256_Update(&ctx
, key
, key_len
);
42 SHA256_End(&ctx
, key0
, NULL
, SHA256_LENGTH
);
43 memset(key0
+ SHA256_LENGTH
, 0, SHA256_BLOCK_SIZE
- SHA256_LENGTH
);
45 memcpy(key0
, key
, key_len
);
46 memset(key0
+ key_len
, 0, SHA256_BLOCK_SIZE
- key_len
);
49 unsigned char padded_key
[SHA256_BLOCK_SIZE
];
50 unsigned char inner_hash
[SHA256_LENGTH
];
52 // XOR key0 with ipad.
53 for (int i
= 0; i
< SHA256_BLOCK_SIZE
; ++i
)
54 padded_key
[i
] = key0
[i
] ^ 0x36;
56 // Compute the inner hash.
58 SHA256_Update(&ctx
, padded_key
, SHA256_BLOCK_SIZE
);
59 SHA256_Update(&ctx
, text
, text_len
);
60 SHA256_End(&ctx
, inner_hash
, NULL
, SHA256_LENGTH
);
62 // XOR key0 with opad.
63 for (int i
= 0; i
< SHA256_BLOCK_SIZE
; ++i
)
64 padded_key
[i
] = key0
[i
] ^ 0x5c;
66 // Compute the outer hash.
68 SHA256_Update(&ctx
, padded_key
, SHA256_BLOCK_SIZE
);
69 SHA256_Update(&ctx
, inner_hash
, SHA256_LENGTH
);
70 SHA256_End(&ctx
, output
, NULL
, output_len
);
75 struct HMACPlatformData
{
77 if (!raw_key_
.empty()) {
78 SecureZeroMemory(&raw_key_
[0], raw_key_
.size());
81 // Destroy the key before releasing the provider.
85 ScopedHCRYPTPROV provider_
;
88 // For HMAC-SHA-256 only.
89 std::vector
<unsigned char> raw_key_
;
92 HMAC::HMAC(HashAlgorithm hash_alg
)
93 : hash_alg_(hash_alg
), plat_(new HMACPlatformData()) {
94 // Only SHA-1 and SHA-256 hash algorithms are supported now.
95 DCHECK(hash_alg_
== SHA1
|| hash_alg_
== SHA256
);
98 bool HMAC::Init(const unsigned char* key
, int key_length
) {
99 if (plat_
->provider_
|| plat_
->key_
|| !plat_
->raw_key_
.empty()) {
100 // Init must not be called more than once on the same HMAC object.
105 if (hash_alg_
== SHA256
) {
106 if (key_length
< SHA256_LENGTH
/ 2)
107 return false; // Key is too short.
108 plat_
->raw_key_
.assign(key
, key
+ key_length
);
112 if (!CryptAcquireContext(plat_
->provider_
.receive(), NULL
, NULL
,
113 PROV_RSA_FULL
, CRYPT_VERIFYCONTEXT
)) {
118 // This code doesn't work on Win2k because PLAINTEXTKEYBLOB and
119 // CRYPT_IPSEC_HMAC_KEY are not supported on Windows 2000. PLAINTEXTKEYBLOB
120 // allows the import of an unencrypted key. For Win2k support, a cubmbersome
121 // exponent-of-one key procedure must be used:
122 // http://support.microsoft.com/kb/228786/en-us
123 // CRYPT_IPSEC_HMAC_KEY allows keys longer than 16 bytes.
130 size_t key_blob_size
= std::max(offsetof(KeyBlob
, key_data
) + key_length
,
132 std::vector
<BYTE
> key_blob_storage
= std::vector
<BYTE
>(key_blob_size
);
133 KeyBlob
* key_blob
= reinterpret_cast<KeyBlob
*>(&key_blob_storage
[0]);
134 key_blob
->header
.bType
= PLAINTEXTKEYBLOB
;
135 key_blob
->header
.bVersion
= CUR_BLOB_VERSION
;
136 key_blob
->header
.reserved
= 0;
137 key_blob
->header
.aiKeyAlg
= CALG_RC2
;
138 key_blob
->key_size
= key_length
;
139 memcpy(key_blob
->key_data
, key
, key_length
);
141 if (!CryptImportKey(plat_
->provider_
, &key_blob_storage
[0],
142 key_blob_storage
.size(), 0, CRYPT_IPSEC_HMAC_KEY
,
143 plat_
->key_
.receive())) {
148 // Destroy the copy of the key.
149 SecureZeroMemory(key_blob
->key_data
, key_length
);
157 bool HMAC::Sign(const base::StringPiece
& data
,
158 unsigned char* digest
,
159 int digest_length
) const {
160 if (hash_alg_
== SHA256
) {
161 if (plat_
->raw_key_
.empty())
163 ComputeHMACSHA256(&plat_
->raw_key_
[0], plat_
->raw_key_
.size(),
164 reinterpret_cast<const unsigned char*>(data
.data()),
165 data
.size(), digest
, digest_length
);
169 if (!plat_
->provider_
|| !plat_
->key_
)
172 if (hash_alg_
!= SHA1
) {
177 ScopedHCRYPTHASH hash
;
178 if (!CryptCreateHash(plat_
->provider_
, CALG_HMAC
, plat_
->key_
, 0,
183 memset(&hmac_info
, 0, sizeof(hmac_info
));
184 hmac_info
.HashAlgid
= CALG_SHA1
;
185 if (!CryptSetHashParam(hash
, HP_HMAC_INFO
,
186 reinterpret_cast<BYTE
*>(&hmac_info
), 0))
189 if (!CryptHashData(hash
, reinterpret_cast<const BYTE
*>(data
.data()),
190 static_cast<DWORD
>(data
.size()), 0))
193 DWORD sha1_size
= digest_length
;
194 return !!CryptGetHashParam(hash
, HP_HASHVAL
, digest
, &sha1_size
, 0);
197 } // namespace crypto