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/chromium-blapi.h"
16 #include "crypto/third_party/nss/chromium-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 if (key_len
< SHA256_BLOCK_SIZE
)
47 memset(key0
+ key_len
, 0, SHA256_BLOCK_SIZE
- key_len
);
50 unsigned char padded_key
[SHA256_BLOCK_SIZE
];
51 unsigned char inner_hash
[SHA256_LENGTH
];
53 // XOR key0 with ipad.
54 for (int i
= 0; i
< SHA256_BLOCK_SIZE
; ++i
)
55 padded_key
[i
] = key0
[i
] ^ 0x36;
57 // Compute the inner hash.
59 SHA256_Update(&ctx
, padded_key
, SHA256_BLOCK_SIZE
);
60 SHA256_Update(&ctx
, text
, text_len
);
61 SHA256_End(&ctx
, inner_hash
, NULL
, SHA256_LENGTH
);
63 // XOR key0 with opad.
64 for (int i
= 0; i
< SHA256_BLOCK_SIZE
; ++i
)
65 padded_key
[i
] = key0
[i
] ^ 0x5c;
67 // Compute the outer hash.
69 SHA256_Update(&ctx
, padded_key
, SHA256_BLOCK_SIZE
);
70 SHA256_Update(&ctx
, inner_hash
, SHA256_LENGTH
);
71 SHA256_End(&ctx
, output
, NULL
, output_len
);
76 struct HMACPlatformData
{
78 if (!raw_key_
.empty()) {
79 SecureZeroMemory(&raw_key_
[0], raw_key_
.size());
82 // Destroy the key before releasing the provider.
86 ScopedHCRYPTPROV provider_
;
89 // For HMAC-SHA-256 only.
90 std::vector
<unsigned char> raw_key_
;
93 HMAC::HMAC(HashAlgorithm hash_alg
)
94 : hash_alg_(hash_alg
), plat_(new HMACPlatformData()) {
95 // Only SHA-1 and SHA-256 hash algorithms are supported now.
96 DCHECK(hash_alg_
== SHA1
|| hash_alg_
== SHA256
);
99 bool HMAC::Init(const unsigned char* key
, int key_length
) {
100 if (plat_
->provider_
|| plat_
->key_
|| !plat_
->raw_key_
.empty()) {
101 // Init must not be called more than once on the same HMAC object.
106 if (hash_alg_
== SHA256
) {
107 if (key_length
< SHA256_LENGTH
/ 2)
108 return false; // Key is too short.
109 plat_
->raw_key_
.assign(key
, key
+ key_length
);
113 if (!CryptAcquireContext(plat_
->provider_
.receive(), NULL
, NULL
,
114 PROV_RSA_FULL
, CRYPT_VERIFYCONTEXT
)) {
119 // This code doesn't work on Win2k because PLAINTEXTKEYBLOB and
120 // CRYPT_IPSEC_HMAC_KEY are not supported on Windows 2000. PLAINTEXTKEYBLOB
121 // allows the import of an unencrypted key. For Win2k support, a cubmbersome
122 // exponent-of-one key procedure must be used:
123 // http://support.microsoft.com/kb/228786/en-us
124 // CRYPT_IPSEC_HMAC_KEY allows keys longer than 16 bytes.
131 size_t key_blob_size
= std::max(offsetof(KeyBlob
, key_data
) + key_length
,
133 std::vector
<BYTE
> key_blob_storage
= std::vector
<BYTE
>(key_blob_size
);
134 KeyBlob
* key_blob
= reinterpret_cast<KeyBlob
*>(&key_blob_storage
[0]);
135 key_blob
->header
.bType
= PLAINTEXTKEYBLOB
;
136 key_blob
->header
.bVersion
= CUR_BLOB_VERSION
;
137 key_blob
->header
.reserved
= 0;
138 key_blob
->header
.aiKeyAlg
= CALG_RC2
;
139 key_blob
->key_size
= key_length
;
140 memcpy(key_blob
->key_data
, key
, key_length
);
142 if (!CryptImportKey(plat_
->provider_
, &key_blob_storage
[0],
143 key_blob_storage
.size(), 0, CRYPT_IPSEC_HMAC_KEY
,
144 plat_
->key_
.receive())) {
149 // Destroy the copy of the key.
150 SecureZeroMemory(key_blob
->key_data
, key_length
);
158 bool HMAC::Sign(const base::StringPiece
& data
,
159 unsigned char* digest
,
160 int digest_length
) const {
161 if (hash_alg_
== SHA256
) {
162 if (plat_
->raw_key_
.empty())
164 ComputeHMACSHA256(&plat_
->raw_key_
[0], plat_
->raw_key_
.size(),
165 reinterpret_cast<const unsigned char*>(data
.data()),
166 data
.size(), digest
, digest_length
);
170 if (!plat_
->provider_
|| !plat_
->key_
)
173 if (hash_alg_
!= SHA1
) {
178 ScopedHCRYPTHASH hash
;
179 if (!CryptCreateHash(plat_
->provider_
, CALG_HMAC
, plat_
->key_
, 0,
184 memset(&hmac_info
, 0, sizeof(hmac_info
));
185 hmac_info
.HashAlgid
= CALG_SHA1
;
186 if (!CryptSetHashParam(hash
, HP_HMAC_INFO
,
187 reinterpret_cast<BYTE
*>(&hmac_info
), 0))
190 if (!CryptHashData(hash
, reinterpret_cast<const BYTE
*>(data
.data()),
191 static_cast<DWORD
>(data
.size()), 0))
194 DWORD sha1_size
= digest_length
;
195 return !!CryptGetHashParam(hash
, HP_HASHVAL
, digest
, &sha1_size
, 0);
198 } // namespace crypto