1 /**
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 /*
21 * XSEC
22 *
23 * WinCAPICryptoHashHMAC := Windows CAPI Implementation of Message digests
24 *
25 * Author(s): Berin Lautenbach
26 *
27 * $Id: WinCAPICryptoHashHMAC.cpp 1833341 2018-06-11 16:25:41Z scantor $
28 *
29 */
30
31 #include <xsec/enc/XSECCryptoException.hpp>
32 #include <xsec/enc/WinCAPI/WinCAPICryptoHashHMAC.hpp>
33 #include <xsec/enc/WinCAPI/WinCAPICryptoProvider.hpp>
34 #include <xsec/enc/WinCAPI/WinCAPICryptoKeyHMAC.hpp>
35
36 #if defined (XSEC_HAVE_WINCAPI)
37
38 #include "../../utils/XSECDOMUtils.hpp"
39
40 #include <memory.h>
41
42 // --------------------------------------------------------------------------------
43 // IPAD/OPAD definitions
44 // --------------------------------------------------------------------------------
45
46 static unsigned char ipad[] = {
47
48 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
49 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
50 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
51 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
52 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
53 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
54 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
55 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
56 };
57
58 static unsigned char opad[] = {
59
60 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
61 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
62 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
63 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
64 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
65 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
66 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
67 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C,
68 };
69
70 // --------------------------------------------------------------------------------
71 // Constructors/Destructors
72 // --------------------------------------------------------------------------------
73
WinCAPICryptoHashHMAC(HCRYPTPROV prov,HashType alg)74 WinCAPICryptoHashHMAC::WinCAPICryptoHashHMAC(HCRYPTPROV prov, HashType alg) {
75
76 m_p = prov;
77 m_h = 0;
78 m_blockSize = 64; // We only know SHA-1 and MD5 at this time - both are 64 bytes
79
80 switch (alg) {
81
82 case (XSECCryptoHash::HASH_SHA1) :
83
84 m_algId = CALG_SHA;
85 break;
86
87 case (XSECCryptoHash::HASH_MD5) :
88
89 m_algId = CALG_MD5;
90 break;
91
92 default :
93
94 m_algId = 0;
95
96 }
97
98 if(m_algId == 0) {
99
100 throw XSECCryptoException(XSECCryptoException::MDError,
101 "WinCAPI:Hash - Unknown algorithm");
102 }
103
104 m_hashType = alg;
105
106
107 }
108
reset()109 void WinCAPICryptoHashHMAC::reset() {
110
111 if (m_h != 0)
112 CryptDestroyHash(m_h);
113
114 }
115
~WinCAPICryptoHashHMAC()116 WinCAPICryptoHashHMAC::~WinCAPICryptoHashHMAC() {
117
118 if (m_h != 0)
119 CryptDestroyHash(m_h);
120
121 }
122
123 // --------------------------------------------------------------------------------
124 // Key manipulation
125 // --------------------------------------------------------------------------------
126
eraseKeys(void)127 void WinCAPICryptoHashHMAC::eraseKeys(void) {
128
129 // Overwrite the ipad/opad calculated key values
130 unsigned char * i = m_ipadKeyed;
131 unsigned char * j = m_opadKeyed;
132
133 for (unsigned int k = 0; k < XSEC_MAX_HASH_BLOCK_SIZE; ++k) {
134 *i++ = 0;
135 *j++ = 0;
136 }
137
138 }
139
setKey(const XSECCryptoKey * key)140 void WinCAPICryptoHashHMAC::setKey(const XSECCryptoKey *key) {
141
142
143 BOOL fResult;
144
145 // Use this to initialise the ipadKeyed/opadKeyed values
146
147 if (key->getKeyType() != XSECCryptoKey::KEY_HMAC) {
148
149 throw XSECCryptoException(XSECCryptoException::MDError,
150 "WinCAPI:HashHMAC - Non HMAC Key passed to HashHMAC");
151
152 }
153
154 if (m_blockSize > XSEC_MAX_HASH_BLOCK_SIZE) {
155
156 throw XSECCryptoException(XSECCryptoException::MDError,
157 "WinCAPI:HashHMAC - Internal error - have got a blocksize bigger than I can handle");
158
159 }
160
161 // Check to see if this is an internal Windows Key
162 if (strEquals(key->getProviderName(), DSIGConstants::s_unicodeStrPROVWinCAPI) &&
163 ((WinCAPICryptoKeyHMAC *) key)->getWinKey() != 0) {
164
165 // Over-ride the local provider for this
166
167 HCRYPTPROV p = ((WinCAPICryptoKeyHMAC *) key)->getWinKeyProv();
168 HCRYPTKEY k = ((WinCAPICryptoKeyHMAC *) key)->getWinKey();
169
170 fResult = CryptCreateHash(
171 p,
172 CALG_HMAC,
173 k,
174 0,
175 &m_h);
176
177 if (fResult == 0 || m_h == 0) {
178 DWORD error = GetLastError();
179 throw XSECCryptoException(XSECCryptoException::MDError,
180 "WinCAPI:Hash::setKey - Error creating internally keyed hash object");
181 }
182
183 // Set the HMAC algorithm
184 HMAC_INFO hi;
185
186 hi.HashAlgid = m_algId;
187 hi.pbInnerString = NULL; // Use default inner and outer strings
188 hi.cbInnerString = 0;
189 hi.pbOuterString = NULL;
190 hi.cbOuterString = 0;
191
192 fResult = CryptSetHashParam(
193 m_h,
194 HP_HMAC_INFO,
195 (BYTE *) &hi,
196 0);
197
198 if (fResult == 0 || m_h == 0) {
199 DWORD error = GetLastError();
200 throw XSECCryptoException(XSECCryptoException::MDError,
201 "WinCAPI:Hash::setKey - Error setting HASH_INFO object");
202 }
203
204
205
206 return;
207
208 }
209
210 // Need to load from raw bit string
211
212 safeBuffer keyBuf;
213 unsigned int keyLen = ((XSECCryptoKeyHMAC *) key)->getKey(keyBuf);
214
215 if (keyLen > m_blockSize) {
216
217 HCRYPTHASH h;
218
219 fResult = CryptCreateHash(
220 m_p,
221 m_algId,
222 0,
223 0,
224 &h);
225
226 if (fResult == 0 || h == 0) {
227 throw XSECCryptoException(XSECCryptoException::MDError,
228 "WinCAPI:Hash::setKey - Error creating hash object");
229 }
230
231 fResult = CryptHashData(
232 h,
233 keyBuf.rawBuffer(),
234 keyLen,
235 0);
236
237 if (fResult == 0 || h == 0) {
238 if (h)
239 CryptDestroyHash(h);
240 throw XSECCryptoException(XSECCryptoException::MDError,
241 "WinCAPI:Hash::setKey - Error hashing key data");
242 }
243
244 BYTE outData[XSEC_MAX_HASH_SIZE];
245 DWORD outDataLen = XSEC_MAX_HASH_SIZE;
246
247 CryptGetHashParam(
248 h,
249 HP_HASHVAL,
250 outData,
251 &outDataLen,
252 0);
253
254 if (fResult == 0 || h == 0) {
255 if (h)
256 CryptDestroyHash(h);
257 throw XSECCryptoException(XSECCryptoException::MDError,
258 "WinCAPI:Hash::setKey - Error getting hash result");
259 }
260
261 keyBuf.sbMemcpyIn(outData, outDataLen);
262 keyLen = outDataLen;
263
264 if (h)
265 CryptDestroyHash(h);
266
267
268 }
269
270 // Now create the ipad and opad keyed values
271 memcpy(m_ipadKeyed, ipad, m_blockSize);
272 memcpy(m_opadKeyed, opad, m_blockSize);
273
274 // XOR with the key
275 for (unsigned int i = 0; i < keyLen; ++i) {
276 m_ipadKeyed[i] = keyBuf[i] ^ m_ipadKeyed[i];
277 m_opadKeyed[i] = keyBuf[i] ^ m_opadKeyed[i];
278 }
279
280
281 // Now create the hash object, and start with the ipad operation
282 fResult = CryptCreateHash(
283 m_p,
284 m_algId,
285 0,
286 0,
287 &m_h);
288
289 if (fResult == 0 || m_h == 0) {
290 throw XSECCryptoException(XSECCryptoException::MDError,
291 "WinCAPI:HashHMAC - Error creating hash object");
292 }
293
294 fResult = CryptHashData(
295 m_h,
296 m_ipadKeyed,
297 m_blockSize,
298 0);
299
300 if (fResult == 0 || m_h == 0) {
301 throw XSECCryptoException(XSECCryptoException::MDError,
302 "WinCAPI:HashHMAC - Error performing initial ipad digest");
303 }
304
305 }
306
307 // --------------------------------------------------------------------------------
308 // Hash operations
309 // --------------------------------------------------------------------------------
310
hash(unsigned char * data,unsigned int length)311 void WinCAPICryptoHashHMAC::hash(unsigned char * data,
312 unsigned int length) {
313
314 if (m_h == 0) {
315 throw XSECCryptoException(XSECCryptoException::MDError,
316 "WinCAPI:HashHMAC::hash() - Called prior to setting key");
317 }
318
319 BOOL fResult = CryptHashData(
320 m_h,
321 data,
322 length,
323 0);
324
325 if (fResult == 0) {
326 throw XSECCryptoException(XSECCryptoException::MDError,
327 "WinCAPI:Hash - Error Hashing Data");
328 }
329
330 }
331
finish(unsigned char * hash,unsigned int maxLength)332 unsigned int WinCAPICryptoHashHMAC::finish(unsigned char * hash,
333 unsigned int maxLength) {
334
335 DWORD retLen;
336 BOOL fResult;
337
338 retLen = XSEC_MAX_HASH_SIZE;
339
340 fResult = CryptGetHashParam(
341 m_h,
342 HP_HASHVAL,
343 m_mdValue,
344 &retLen,
345 0);
346
347 if (fResult == 0) {
348 throw XSECCryptoException(XSECCryptoException::MDError,
349 "WinCAPI:Hash - Error getting hash value");
350 }
351
352 // Perform the opad operation
353 HCRYPTHASH h;
354 fResult = CryptCreateHash(
355 m_p,
356 m_algId,
357 0,
358 0,
359 &h);
360
361 if (fResult == 0 || h == 0) {
362 throw XSECCryptoException(XSECCryptoException::MDError,
363 "WinCAPI:Hash::finish - Error creating hash object for opad operation");
364 }
365
366 fResult = CryptHashData(
367 h,
368 m_opadKeyed,
369 m_blockSize,
370 0);
371
372 if (fResult == 0 || h == 0) {
373 if (h)
374 CryptDestroyHash(h);
375 throw XSECCryptoException(XSECCryptoException::MDError,
376 "WinCAPI:Hash::finish - Error hashing opad data");
377 }
378
379 fResult = CryptHashData(
380 h,
381 m_mdValue,
382 retLen,
383 0);
384
385 if (fResult == 0 || h == 0) {
386 if (h)
387 CryptDestroyHash(h);
388 throw XSECCryptoException(XSECCryptoException::MDError,
389 "WinCAPI:Hash::finish - Error hashing ipad hash to opad");
390 }
391
392 // Read out the final hash
393 retLen = XSEC_MAX_HASH_SIZE;
394
395 fResult = CryptGetHashParam(
396 h,
397 HP_HASHVAL,
398 m_mdValue,
399 &retLen,
400 0);
401
402 CryptDestroyHash(h);
403
404 m_mdLen = retLen;
405 retLen = (maxLength > m_mdLen ? m_mdLen : maxLength);
406 memcpy(hash, m_mdValue, retLen);
407
408 return (unsigned int) retLen;
409
410 }
411
412 // Get information
413
getHashType(void) const414 XSECCryptoHash::HashType WinCAPICryptoHashHMAC::getHashType(void) const {
415
416 return m_hashType; // This could be any kind of hash
417
418 }
419
420 #endif /* XSEC_HAVE_WINCAPI */
421