| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| /* |
| * XSEC |
| * |
| * WinCAPICryptoHashHMAC := Windows CAPI Implementation of Message digests |
| * |
| * Author(s): Berin Lautenbach |
| * |
| * $Id$ |
| * |
| */ |
| |
| #include <xsec/enc/XSECCryptoException.hpp> |
| #include <xsec/enc/WinCAPI/WinCAPICryptoHashHMAC.hpp> |
| #include <xsec/enc/WinCAPI/WinCAPICryptoProvider.hpp> |
| #include <xsec/enc/WinCAPI/WinCAPICryptoKeyHMAC.hpp> |
| |
| #if defined (XSEC_HAVE_WINCAPI) |
| |
| #include "../../utils/XSECDOMUtils.hpp" |
| |
| #include <memory.h> |
| |
| // -------------------------------------------------------------------------------- |
| // IPAD/OPAD definitions |
| // -------------------------------------------------------------------------------- |
| |
| static unsigned char ipad[] = { |
| |
| 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, |
| 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, |
| 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, |
| 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, |
| 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, |
| 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, |
| 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, |
| 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, |
| }; |
| |
| static unsigned char opad[] = { |
| |
| 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, |
| 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, |
| 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, |
| 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, |
| 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, |
| 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, |
| 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, |
| 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, 0x5C, |
| }; |
| |
| // -------------------------------------------------------------------------------- |
| // Constructors/Destructors |
| // -------------------------------------------------------------------------------- |
| |
| WinCAPICryptoHashHMAC::WinCAPICryptoHashHMAC(HCRYPTPROV prov, HashType alg) { |
| |
| m_p = prov; |
| m_h = 0; |
| m_blockSize = 64; // We only know SHA-1 and MD5 at this time - both are 64 bytes |
| |
| switch (alg) { |
| |
| case (XSECCryptoHash::HASH_SHA1) : |
| |
| m_algId = CALG_SHA; |
| break; |
| |
| case (XSECCryptoHash::HASH_MD5) : |
| |
| m_algId = CALG_MD5; |
| break; |
| |
| default : |
| |
| m_algId = 0; |
| |
| } |
| |
| if(m_algId == 0) { |
| |
| throw XSECCryptoException(XSECCryptoException::MDError, |
| "WinCAPI:Hash - Unknown algorithm"); |
| } |
| |
| m_hashType = alg; |
| |
| |
| } |
| |
| void WinCAPICryptoHashHMAC::reset() { |
| |
| if (m_h != 0) |
| CryptDestroyHash(m_h); |
| |
| } |
| |
| WinCAPICryptoHashHMAC::~WinCAPICryptoHashHMAC() { |
| |
| if (m_h != 0) |
| CryptDestroyHash(m_h); |
| |
| } |
| |
| // -------------------------------------------------------------------------------- |
| // Key manipulation |
| // -------------------------------------------------------------------------------- |
| |
| void WinCAPICryptoHashHMAC::eraseKeys(void) { |
| |
| // Overwrite the ipad/opad calculated key values |
| unsigned char * i = m_ipadKeyed; |
| unsigned char * j = m_opadKeyed; |
| |
| for (unsigned int k = 0; k < XSEC_MAX_HASH_BLOCK_SIZE; ++k) { |
| *i++ = 0; |
| *j++ = 0; |
| } |
| |
| } |
| |
| void WinCAPICryptoHashHMAC::setKey(const XSECCryptoKey *key) { |
| |
| |
| BOOL fResult; |
| |
| // Use this to initialise the ipadKeyed/opadKeyed values |
| |
| if (key->getKeyType() != XSECCryptoKey::KEY_HMAC) { |
| |
| throw XSECCryptoException(XSECCryptoException::MDError, |
| "WinCAPI:HashHMAC - Non HMAC Key passed to HashHMAC"); |
| |
| } |
| |
| if (m_blockSize > XSEC_MAX_HASH_BLOCK_SIZE) { |
| |
| throw XSECCryptoException(XSECCryptoException::MDError, |
| "WinCAPI:HashHMAC - Internal error - have got a blocksize bigger than I can handle"); |
| |
| } |
| |
| // Check to see if this is an internal Windows Key |
| if (strEquals(key->getProviderName(), DSIGConstants::s_unicodeStrPROVWinCAPI) && |
| ((WinCAPICryptoKeyHMAC *) key)->getWinKey() != 0) { |
| |
| // Over-ride the local provider for this |
| |
| HCRYPTPROV p = ((WinCAPICryptoKeyHMAC *) key)->getWinKeyProv(); |
| HCRYPTKEY k = ((WinCAPICryptoKeyHMAC *) key)->getWinKey(); |
| |
| fResult = CryptCreateHash( |
| p, |
| CALG_HMAC, |
| k, |
| 0, |
| &m_h); |
| |
| if (fResult == 0 || m_h == 0) { |
| DWORD error = GetLastError(); |
| throw XSECCryptoException(XSECCryptoException::MDError, |
| "WinCAPI:Hash::setKey - Error creating internally keyed hash object"); |
| } |
| |
| // Set the HMAC algorithm |
| HMAC_INFO hi; |
| |
| hi.HashAlgid = m_algId; |
| hi.pbInnerString = NULL; // Use default inner and outer strings |
| hi.cbInnerString = 0; |
| hi.pbOuterString = NULL; |
| hi.cbOuterString = 0; |
| |
| fResult = CryptSetHashParam( |
| m_h, |
| HP_HMAC_INFO, |
| (BYTE *) &hi, |
| 0); |
| |
| if (fResult == 0 || m_h == 0) { |
| DWORD error = GetLastError(); |
| throw XSECCryptoException(XSECCryptoException::MDError, |
| "WinCAPI:Hash::setKey - Error setting HASH_INFO object"); |
| } |
| |
| |
| |
| return; |
| |
| } |
| |
| // Need to load from raw bit string |
| |
| safeBuffer keyBuf; |
| unsigned int keyLen = ((XSECCryptoKeyHMAC *) key)->getKey(keyBuf); |
| |
| if (keyLen > m_blockSize) { |
| |
| HCRYPTHASH h; |
| |
| fResult = CryptCreateHash( |
| m_p, |
| m_algId, |
| 0, |
| 0, |
| &h); |
| |
| if (fResult == 0 || h == 0) { |
| throw XSECCryptoException(XSECCryptoException::MDError, |
| "WinCAPI:Hash::setKey - Error creating hash object"); |
| } |
| |
| fResult = CryptHashData( |
| h, |
| keyBuf.rawBuffer(), |
| keyLen, |
| 0); |
| |
| if (fResult == 0 || h == 0) { |
| if (h) |
| CryptDestroyHash(h); |
| throw XSECCryptoException(XSECCryptoException::MDError, |
| "WinCAPI:Hash::setKey - Error hashing key data"); |
| } |
| |
| BYTE outData[XSEC_MAX_HASH_SIZE]; |
| DWORD outDataLen = XSEC_MAX_HASH_SIZE; |
| |
| CryptGetHashParam( |
| h, |
| HP_HASHVAL, |
| outData, |
| &outDataLen, |
| 0); |
| |
| if (fResult == 0 || h == 0) { |
| if (h) |
| CryptDestroyHash(h); |
| throw XSECCryptoException(XSECCryptoException::MDError, |
| "WinCAPI:Hash::setKey - Error getting hash result"); |
| } |
| |
| keyBuf.sbMemcpyIn(outData, outDataLen); |
| keyLen = outDataLen; |
| |
| if (h) |
| CryptDestroyHash(h); |
| |
| |
| } |
| |
| // Now create the ipad and opad keyed values |
| memcpy(m_ipadKeyed, ipad, m_blockSize); |
| memcpy(m_opadKeyed, opad, m_blockSize); |
| |
| // XOR with the key |
| for (unsigned int i = 0; i < keyLen; ++i) { |
| m_ipadKeyed[i] = keyBuf[i] ^ m_ipadKeyed[i]; |
| m_opadKeyed[i] = keyBuf[i] ^ m_opadKeyed[i]; |
| } |
| |
| |
| // Now create the hash object, and start with the ipad operation |
| fResult = CryptCreateHash( |
| m_p, |
| m_algId, |
| 0, |
| 0, |
| &m_h); |
| |
| if (fResult == 0 || m_h == 0) { |
| throw XSECCryptoException(XSECCryptoException::MDError, |
| "WinCAPI:HashHMAC - Error creating hash object"); |
| } |
| |
| fResult = CryptHashData( |
| m_h, |
| m_ipadKeyed, |
| m_blockSize, |
| 0); |
| |
| if (fResult == 0 || m_h == 0) { |
| throw XSECCryptoException(XSECCryptoException::MDError, |
| "WinCAPI:HashHMAC - Error performing initial ipad digest"); |
| } |
| |
| } |
| |
| // -------------------------------------------------------------------------------- |
| // Hash operations |
| // -------------------------------------------------------------------------------- |
| |
| void WinCAPICryptoHashHMAC::hash(unsigned char * data, |
| unsigned int length) { |
| |
| if (m_h == 0) { |
| throw XSECCryptoException(XSECCryptoException::MDError, |
| "WinCAPI:HashHMAC::hash() - Called prior to setting key"); |
| } |
| |
| BOOL fResult = CryptHashData( |
| m_h, |
| data, |
| length, |
| 0); |
| |
| if (fResult == 0) { |
| throw XSECCryptoException(XSECCryptoException::MDError, |
| "WinCAPI:Hash - Error Hashing Data"); |
| } |
| |
| } |
| |
| unsigned int WinCAPICryptoHashHMAC::finish(unsigned char * hash, |
| unsigned int maxLength) { |
| |
| DWORD retLen; |
| BOOL fResult; |
| |
| retLen = XSEC_MAX_HASH_SIZE; |
| |
| fResult = CryptGetHashParam( |
| m_h, |
| HP_HASHVAL, |
| m_mdValue, |
| &retLen, |
| 0); |
| |
| if (fResult == 0) { |
| throw XSECCryptoException(XSECCryptoException::MDError, |
| "WinCAPI:Hash - Error getting hash value"); |
| } |
| |
| // Perform the opad operation |
| HCRYPTHASH h; |
| fResult = CryptCreateHash( |
| m_p, |
| m_algId, |
| 0, |
| 0, |
| &h); |
| |
| if (fResult == 0 || h == 0) { |
| throw XSECCryptoException(XSECCryptoException::MDError, |
| "WinCAPI:Hash::finish - Error creating hash object for opad operation"); |
| } |
| |
| fResult = CryptHashData( |
| h, |
| m_opadKeyed, |
| m_blockSize, |
| 0); |
| |
| if (fResult == 0 || h == 0) { |
| if (h) |
| CryptDestroyHash(h); |
| throw XSECCryptoException(XSECCryptoException::MDError, |
| "WinCAPI:Hash::finish - Error hashing opad data"); |
| } |
| |
| fResult = CryptHashData( |
| h, |
| m_mdValue, |
| retLen, |
| 0); |
| |
| if (fResult == 0 || h == 0) { |
| if (h) |
| CryptDestroyHash(h); |
| throw XSECCryptoException(XSECCryptoException::MDError, |
| "WinCAPI:Hash::finish - Error hashing ipad hash to opad"); |
| } |
| |
| // Read out the final hash |
| retLen = XSEC_MAX_HASH_SIZE; |
| |
| fResult = CryptGetHashParam( |
| h, |
| HP_HASHVAL, |
| m_mdValue, |
| &retLen, |
| 0); |
| |
| CryptDestroyHash(h); |
| |
| m_mdLen = retLen; |
| retLen = (maxLength > m_mdLen ? m_mdLen : maxLength); |
| memcpy(hash, m_mdValue, retLen); |
| |
| return (unsigned int) retLen; |
| |
| } |
| |
| // Get information |
| |
| XSECCryptoHash::HashType WinCAPICryptoHashHMAC::getHashType(void) const { |
| |
| return m_hashType; // This could be any kind of hash |
| |
| } |
| |
| #endif /* XSEC_HAVE_WINCAPI */ |