| /** |
| * 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 |
| * |
| * WinCAPICryptoKeyRSA := RSA Keys |
| * |
| * Author(s): Berin Lautenbach |
| * |
| * $Id$ |
| * |
| */ |
| |
| #if defined (XSEC_HAVE_WINCAPI) |
| |
| #include <xsec/enc/XSECCryptoException.hpp> |
| #include <xsec/enc/WinCAPI/WinCAPICryptoProvider.hpp> |
| #include <xsec/enc/WinCAPI/WinCAPICryptoKeyRSA.hpp> |
| #include <xsec/enc/XSCrypt/XSCryptCryptoBase64.hpp> |
| #include <xsec/framework/XSECError.hpp> |
| |
| #include "../../utils/XSECAlgorithmSupport.hpp" |
| |
| #include <xercesc/util/Janitor.hpp> |
| |
| XSEC_USING_XERCES(ArrayJanitor); |
| |
| #if !defined (CRYPT_OAEP) |
| # define CRYPT_OAEP 0x00000040 |
| # define KP_OAEP_PARAMS 36 |
| #endif |
| |
| #if !defined (CRYPT_DECRYPT_RSA_NO_PADDING_CHECK) |
| # define CRYPT_DECRYPT_RSA_NO_PADDING_CHECK 0x00000020 |
| #endif |
| |
| WinCAPICryptoKeyRSA::WinCAPICryptoKeyRSA(HCRYPTPROV prov) { |
| |
| // Create a new key to be loaded as we go |
| |
| m_key = 0; |
| m_p = prov; |
| m_keySpec = 0; |
| |
| mp_exponent = NULL; |
| m_exponentLen = 0; |
| mp_modulus = NULL; |
| m_modulusLen = 0; |
| }; |
| |
| WinCAPICryptoKeyRSA::~WinCAPICryptoKeyRSA() { |
| |
| // If we have a RSA, delete it |
| |
| if (m_key != 0) |
| CryptDestroyKey(m_key); |
| |
| if (mp_exponent) |
| delete[] mp_exponent; |
| if (mp_modulus) |
| delete[] mp_modulus; |
| }; |
| |
| WinCAPICryptoKeyRSA::WinCAPICryptoKeyRSA(HCRYPTPROV prov, |
| HCRYPTKEY k) : m_p(prov) { |
| |
| m_key = k; // NOTE - We OWN this handle |
| m_keySpec = 0; |
| |
| mp_exponent = mp_modulus = NULL; |
| m_exponentLen = m_modulusLen = 0; |
| } |
| |
| WinCAPICryptoKeyRSA::WinCAPICryptoKeyRSA(HCRYPTPROV prov, |
| DWORD keySpec, |
| bool isPrivate) : m_p(prov) { |
| |
| if (isPrivate == false) { |
| |
| throw XSECCryptoException(XSECCryptoException::RSAError, |
| "WinCAPICryptoKeyRSA - Public keys defined via keySpec ctor not yet supported"); |
| |
| |
| } |
| |
| if (!CryptGetUserKey(prov, keySpec, &m_key)) { |
| throw XSECCryptoException(XSECCryptoException::RSAError, |
| "WinCAPI:RSA Unable to retrieve user key"); |
| } |
| |
| //m_key = 0; |
| m_keySpec = keySpec; |
| |
| mp_exponent = mp_modulus = NULL; |
| m_exponentLen = m_modulusLen = 0; |
| } |
| |
| const XMLCh * WinCAPICryptoKeyRSA::getProviderName() const { |
| return DSIGConstants::s_unicodeStrPROVWinCAPI; |
| } |
| |
| // Generic key functions |
| |
| XSECCryptoKey::KeyType WinCAPICryptoKeyRSA::getKeyType() const { |
| |
| // Find out what we have |
| if (m_key == 0) { |
| |
| if (m_keySpec != 0) |
| return KEY_RSA_PRIVATE; |
| |
| if (mp_exponent == NULL || |
| mp_modulus == NULL) |
| return KEY_NONE; |
| else |
| return KEY_RSA_PUBLIC; |
| |
| } |
| |
| if (m_keySpec != 0) |
| return KEY_RSA_PAIR; |
| |
| return KEY_RSA_PUBLIC; |
| } |
| |
| |
| // -------------------------------------------------------------------------------- |
| // Load key from parameters |
| // -------------------------------------------------------------------------------- |
| |
| void WinCAPICryptoKeyRSA::loadPublicModulusBase64BigNums(const char* b64, unsigned int len) { |
| |
| if (mp_modulus != NULL) { |
| delete[] mp_modulus; |
| mp_modulus = NULL; // In case we get an exception |
| } |
| |
| mp_modulus = WinCAPICryptoProvider::b642WinBN(b64, len, m_modulusLen); |
| |
| } |
| |
| void WinCAPICryptoKeyRSA::loadPublicExponentBase64BigNums(const char* b64, unsigned int len) { |
| |
| if (mp_exponent != NULL) { |
| delete[] mp_exponent; |
| mp_exponent = NULL; // In case we get an exception |
| } |
| |
| mp_exponent = WinCAPICryptoProvider::b642WinBN(b64, len, m_exponentLen); |
| } |
| |
| HCRYPTKEY WinCAPICryptoKeyRSA::importKey() const { |
| |
| if (m_key != 0 || |
| mp_exponent == NULL || |
| mp_modulus == NULL) |
| |
| return m_key; |
| |
| |
| // Create a RSA Public-Key blob |
| |
| // First build a buffer to hold everything |
| |
| BYTE * blobBuffer; |
| unsigned int blobBufferLen = WINCAPI_BLOBHEADERLEN + WINCAPI_RSAPUBKEYLEN + m_modulusLen; |
| XSECnew(blobBuffer, BYTE[blobBufferLen]); |
| ArrayJanitor<BYTE> j_blobBuffer(blobBuffer); |
| |
| // Blob header |
| BLOBHEADER * header = (BLOBHEADER *) blobBuffer; |
| |
| header->bType = PUBLICKEYBLOB; |
| header->bVersion = 0x02; // We are using a version 2 blob |
| header->reserved = 0; |
| header->aiKeyAlg = CALG_RSA_SIGN; |
| |
| // Now the public key header |
| RSAPUBKEY * pubkey = (RSAPUBKEY *) (blobBuffer + WINCAPI_BLOBHEADERLEN); |
| |
| pubkey->magic = 0x31415352; // ASCII encoding of RSA1 |
| pubkey->bitlen = m_modulusLen * 8; // Number of bits in prime modulus |
| pubkey->pubexp = 0; |
| BYTE * i = ((BYTE *) &(pubkey->pubexp)); |
| for (unsigned int j = 0; j < m_exponentLen; ++j) |
| *i++ = mp_exponent[j]; |
| |
| // Now copy in the modulus |
| i = (BYTE *) (pubkey); |
| i += WINCAPI_RSAPUBKEYLEN; |
| |
| memcpy(i, mp_modulus, m_modulusLen); |
| |
| // Now that we have the blob, import |
| BOOL fResult = CryptImportKey( |
| m_p, |
| blobBuffer, |
| blobBufferLen, |
| 0, // Not signed |
| 0, // No flags |
| &m_key); |
| |
| if (fResult == 0) { |
| |
| throw XSECCryptoException(XSECCryptoException::RSAError, |
| "WinCAPI:RSA Error attempting to import key parameters"); |
| |
| } |
| |
| return m_key; |
| } |
| |
| |
| // -------------------------------------------------------------------------------- |
| // Verify a signature encoded as a Base64 string |
| // -------------------------------------------------------------------------------- |
| |
| bool WinCAPICryptoKeyRSA::verifySHA1PKCS1Base64Signature(const unsigned char * hashBuf, |
| unsigned int hashLen, |
| const char * base64Signature, |
| unsigned int sigLen, |
| XSECCryptoHash::HashType type) const { |
| |
| // Use the currently loaded key to validate the Base64 encoded signature |
| |
| if (m_key == 0) { |
| |
| // Try to import from the parameters |
| importKey(); |
| |
| if (m_key == 0) { |
| throw XSECCryptoException(XSECCryptoException::RSAError, |
| "WinCAPI:RSA - Attempt to validate signature with empty key"); |
| } |
| } |
| |
| /* Is this a hash we support? */ |
| ALG_ID alg; |
| switch (type) { |
| case (XSECCryptoHash::HASH_MD5): |
| alg = CALG_MD5; |
| break; |
| case (XSECCryptoHash::HASH_SHA1): |
| alg=CALG_SHA1; |
| break; |
| default: |
| throw XSECCryptoException(XSECCryptoException::RSAError, |
| "WinCAPI:RSA Unsupported hash algorithm for RSA sign - only MD5 or SHA1 supported"); |
| } |
| |
| // Decode the signature |
| unsigned char * rawSig; |
| DWORD rawSigLen; |
| XSECnew(rawSig, BYTE [sigLen]); |
| ArrayJanitor<BYTE> j_rawSig(rawSig); |
| |
| // Decode the signature |
| XSCryptCryptoBase64 b64; |
| |
| b64.decodeInit(); |
| rawSigLen = b64.decode((unsigned char *) base64Signature, sigLen, rawSig, sigLen); |
| rawSigLen += b64.decodeFinish(&rawSig[rawSigLen], sigLen - rawSigLen); |
| |
| BYTE * rawSigFinal; |
| XSECnew(rawSigFinal, BYTE[rawSigLen]); |
| ArrayJanitor<BYTE> j_rawSigFinal(rawSigFinal); |
| |
| BYTE * j, *l; |
| j = rawSig; |
| l = rawSigFinal + rawSigLen - 1; |
| |
| while (l >= rawSigFinal) { |
| *l-- = *j++; |
| } |
| |
| // Have to create a Windows hash object and feed in the hash |
| BOOL fResult; |
| HCRYPTHASH h; |
| fResult = CryptCreateHash(m_p, |
| alg, |
| 0, |
| 0, |
| &h); |
| |
| if (!fResult) { |
| throw XSECCryptoException(XSECCryptoException::RSAError, |
| "WinCAPI:RSA - Error creating Windows Hash Object"); |
| } |
| |
| // Feed the hash value into the newly created hash object |
| fResult = CryptSetHashParam( |
| h, |
| HP_HASHVAL, |
| (unsigned char *) hashBuf, |
| 0); |
| |
| if (!fResult) { |
| throw XSECCryptoException(XSECCryptoException::RSAError, |
| "WinCAPI:RSA - Error Setting Hash Value in Windows Hash object"); |
| } |
| |
| // Now validate |
| fResult = CryptVerifySignature( |
| h, |
| rawSigFinal, |
| rawSigLen, |
| m_key, |
| NULL, |
| 0); |
| |
| if (!fResult) { |
| |
| DWORD error = GetLastError(); |
| |
| if (error != NTE_BAD_SIGNATURE) { |
| if (h) |
| CryptDestroyHash(h); |
| throw XSECCryptoException(XSECCryptoException::RSAError, |
| "WinCAPI:RSA - Error occurred in RSA validation"); |
| } |
| |
| if (h) |
| CryptDestroyHash(h); |
| return false; |
| } |
| |
| if (h) |
| CryptDestroyHash(h); |
| return true; |
| } |
| |
| // -------------------------------------------------------------------------------- |
| // Sign and encode result as a Base64 string |
| // -------------------------------------------------------------------------------- |
| |
| |
| unsigned int WinCAPICryptoKeyRSA::signSHA1PKCS1Base64Signature(unsigned char * hashBuf, |
| unsigned int hashLen, |
| char * base64SignatureBuf, |
| unsigned int base64SignatureBufLen, |
| XSECCryptoHash::HashType type) const { |
| |
| // Sign a pre-calculated hash using this key |
| |
| if (m_keySpec == 0) { |
| throw XSECCryptoException(XSECCryptoException::RSAError, |
| "WinCAPI:RSA - Attempt to sign data using a public or un-loaded key"); |
| } |
| |
| /* Is this a hash we support? */ |
| ALG_ID alg; |
| switch (type) { |
| case (XSECCryptoHash::HASH_MD5): |
| alg = CALG_MD5; |
| break; |
| case (XSECCryptoHash::HASH_SHA1): |
| alg = CALG_SHA1; |
| break; |
| default: |
| throw XSECCryptoException(XSECCryptoException::RSAError, |
| "WinCAPI:RSA Unsupported hash algorithm for RSA sign - only MD5 or SHA1 supported"); |
| } |
| |
| // Have to create a Windows hash object and feed in the hash |
| BOOL fResult; |
| HCRYPTHASH h; |
| fResult = CryptCreateHash(m_p, |
| alg, |
| 0, |
| 0, |
| &h); |
| |
| if (!fResult) { |
| throw XSECCryptoException(XSECCryptoException::RSAError, |
| "WinCAPI:RSA - Error creating Windows Hash Object"); |
| } |
| |
| // Feed the hash value into the newly created hash object |
| fResult = CryptSetHashParam( |
| h, |
| HP_HASHVAL, |
| hashBuf, |
| 0); |
| |
| if (!fResult) { |
| if (h) |
| CryptDestroyHash(h); |
| throw XSECCryptoException(XSECCryptoException::RSAError, |
| "WinCAPI:RSA - Error Setting Hash Value in Windows Hash object"); |
| } |
| |
| // Now sign |
| DWORD rawSigLen; |
| fResult = CryptSignHash( |
| h, |
| m_keySpec, |
| NULL, |
| 0, |
| NULL, |
| &rawSigLen); |
| |
| if (!fResult || rawSigLen < 1) { |
| |
| if (h) |
| CryptDestroyHash(h); |
| throw XSECCryptoException(XSECCryptoException::RSAError, |
| "WinCAPI:RSA - Error occurred obtaining RSA sig length"); |
| } |
| |
| BYTE * rawSig; |
| XSECnew(rawSig, BYTE[rawSigLen]); |
| ArrayJanitor<BYTE> j_rawSig(rawSig); |
| |
| fResult = CryptSignHash( |
| h, |
| m_keySpec, |
| NULL, |
| 0, |
| rawSig, |
| &rawSigLen); |
| |
| if (!fResult || rawSigLen < 1) { |
| |
| // Free the hash |
| if (h) |
| CryptDestroyHash(h); |
| |
| throw XSECCryptoException(XSECCryptoException::RSAError, |
| "WinCAPI:RSA - Error occurred signing hash"); |
| } |
| |
| // Free the hash |
| if (h) |
| CryptDestroyHash(h); |
| |
| // Now encode into a signature block |
| BYTE *rawSigFinal; |
| XSECnew(rawSigFinal, BYTE[rawSigLen]); |
| ArrayJanitor<BYTE> j_rawSigFinal(rawSigFinal); |
| |
| BYTE * i, * j; |
| |
| i = rawSig; |
| j = rawSigFinal + rawSigLen - 1; |
| |
| while (j >= rawSigFinal) { |
| *j-- = *i++; |
| } |
| |
| // Now encode |
| XSCryptCryptoBase64 b64; |
| b64.encodeInit(); |
| unsigned int ret = b64.encode(rawSigFinal, rawSigLen, (unsigned char *) base64SignatureBuf, base64SignatureBufLen); |
| ret += b64.encodeFinish((unsigned char *) &base64SignatureBuf[ret], base64SignatureBufLen - ret); |
| |
| return ret; |
| } |
| |
| XSECCryptoKey * WinCAPICryptoKeyRSA::clone() const { |
| |
| WinCAPICryptoKeyRSA * ret; |
| |
| XSECnew(ret, WinCAPICryptoKeyRSA(m_p)); |
| |
| if (m_key != 0) { |
| |
| // CryptDuplicateKey is not supported in Windows NT, so we need to export and then |
| // reimport the key to get a copy |
| |
| BYTE keyBuf[2048]; |
| DWORD keyBufLen = 2048; |
| CryptExportKey(m_key, 0, PUBLICKEYBLOB, 0, keyBuf, &keyBufLen); |
| |
| // Now re-import |
| CryptImportKey(m_p, keyBuf, keyBufLen, NULL, 0, &ret->m_key); |
| } |
| |
| ret->m_keySpec = m_keySpec; |
| |
| ret->m_exponentLen = m_exponentLen; |
| if (mp_exponent != NULL) { |
| XSECnew(ret->mp_exponent, BYTE[m_exponentLen]); |
| memcpy(ret->mp_exponent, mp_exponent, m_exponentLen); |
| } |
| else |
| ret->mp_exponent = NULL; |
| |
| ret->m_modulusLen = m_modulusLen; |
| if (mp_modulus != NULL) { |
| XSECnew(ret->mp_modulus, BYTE[m_modulusLen]); |
| memcpy(ret->mp_modulus, mp_modulus, m_modulusLen); |
| } |
| else |
| ret->mp_modulus = NULL; |
| |
| return ret; |
| } |
| |
| // -------------------------------------------------------------------------------- |
| // decrypt a buffer |
| // -------------------------------------------------------------------------------- |
| |
| unsigned int WinCAPICryptoKeyRSA::privateDecrypt(const unsigned char * inBuf, |
| unsigned char * plainBuf, |
| unsigned int inLength, |
| unsigned int maxOutLength, |
| PaddingType padding, |
| const XMLCh* hashURI, |
| const XMLCh* mgfURI, |
| unsigned char* params, |
| unsigned int paramsLen) const { |
| |
| // Perform a decrypt |
| if (m_key == NULL) { |
| throw XSECCryptoException(XSECCryptoException::RSAError, |
| "WinCAPI:RSA - Attempt to decrypt data with empty key"); |
| } |
| |
| // Have to reverse ordering of input : |
| DWORD decryptSize = inLength; |
| // memcpy(plainBuf, inBuf, inLength); |
| for (unsigned int i = 0; i < inLength; ++i) { |
| plainBuf[i] = inBuf[inLength - 1 - i]; |
| } |
| |
| switch (padding) { |
| |
| case XSECCryptoKeyRSA::PAD_PKCS_1_5 : |
| |
| if (!CryptDecrypt(m_key, |
| 0, |
| TRUE, |
| 0, |
| plainBuf, |
| &decryptSize)) { |
| |
| throw XSECCryptoException(XSECCryptoException::RSAError, |
| "WinCAPI:RSA privateKeyDecrypt - Error Decrypting PKCS1_5 padded RSA encrypt"); |
| } |
| |
| break; |
| |
| case XSECCryptoKeyRSA::PAD_OAEP : |
| |
| if (XSECAlgorithmSupport::getMGF1HashType(mgfURI) != XSECCryptoHash::HASH_SHA1) { |
| throw XSECCryptoException(XSECCryptoException::UnsupportedAlgorithm, |
| "WinCAPI:RSA - Unsupported OAEP MGF algorithm"); |
| } |
| |
| if (XSECAlgorithmSupport::getHashType(hashURI) != XSECCryptoHash::HASH_SHA1) { |
| throw XSECCryptoException(XSECCryptoException::UnsupportedAlgorithm, |
| "WinCAPI:RSA - Unsupported OAEP digest algorithm"); |
| } |
| else if (paramsLen > 0) { |
| throw XSECCryptoException(XSECCryptoException::UnsupportedError, |
| "WinCAPI::setOAEPParams - OAEP parameters are not supported by Windows Crypto API"); |
| } |
| |
| if (!CryptDecrypt(m_key, |
| 0, |
| TRUE, |
| CRYPT_OAEP, |
| plainBuf, |
| &decryptSize)) { |
| |
| throw XSECCryptoException(XSECCryptoException::RSAError, |
| "WinCAPI:RSA privateKeyDecrypt - Error Decrypting PKCS1v2 OAEP padded RSA encrypt"); |
| } |
| |
| break; |
| |
| |
| default : |
| throw XSECCryptoException(XSECCryptoException::RSAError, |
| "WiNCAPI:RSA - Unknown padding method"); |
| } |
| |
| |
| return decryptSize; |
| } |
| |
| // -------------------------------------------------------------------------------- |
| // encrypt a buffer |
| // -------------------------------------------------------------------------------- |
| |
| unsigned int WinCAPICryptoKeyRSA::publicEncrypt(const unsigned char* inBuf, |
| unsigned char* cipherBuf, |
| unsigned int inLength, |
| unsigned int maxOutLength, |
| PaddingType padding, |
| const XMLCh* hashURI, |
| const XMLCh* mgfURI, |
| unsigned char* params, |
| unsigned int paramsLen) const { |
| |
| // Perform an encrypt |
| if (m_key == 0) { |
| throw XSECCryptoException(XSECCryptoException::RSAError, |
| "WinCAPI:RSA - Attempt to encrypt data with empty key"); |
| } |
| |
| DWORD encryptSize = inLength; |
| memcpy(cipherBuf, inBuf, inLength); |
| |
| switch (padding) { |
| |
| case XSECCryptoKeyRSA::PAD_PKCS_1_5 : |
| |
| if (!CryptEncrypt(m_key, |
| 0, /* No Hash */ |
| TRUE, /* Is Final */ |
| 0, /* No flags */ |
| cipherBuf, |
| &encryptSize, |
| maxOutLength)) { |
| |
| throw XSECCryptoException(XSECCryptoException::RSAError, |
| "WinCAPI:RSA publicKeyEncrypt - Error performing encrypt"); |
| } |
| |
| if (encryptSize <= 0) { |
| throw XSECCryptoException(XSECCryptoException::RSAError, |
| "WinCAPI:RSA publicKeyEncrypt - Error performing PKCS1_5 padded RSA encrypt"); |
| } |
| |
| break; |
| |
| case XSECCryptoKeyRSA::PAD_OAEP : |
| |
| if (XSECAlgorithmSupport::getHashType(hashURI) != XSECCryptoHash::HASH_SHA1) { |
| throw XSECCryptoException(XSECCryptoException::UnsupportedAlgorithm, |
| "WinCAPI:RSA - OAEP padding method requires SHA-1 digest method"); |
| } |
| else if (XSECAlgorithmSupport::getMGF1HashType(mgfURI) != XSECCryptoHash::HASH_SHA1) { |
| throw XSECCryptoException(XSECCryptoException::UnsupportedAlgorithm, |
| "WinCAPI:RSA - Unsupported OAEP MGF algorithm"); |
| } |
| else if (paramsLen > 0) { |
| throw XSECCryptoException(XSECCryptoException::UnsupportedError, |
| "WinCAPI::setOAEPParams - OAEP parameters are not supported by Windows Crypto API"); |
| } |
| |
| if (!CryptEncrypt(m_key, |
| 0, /* No Hash */ |
| TRUE, /* Is Final */ |
| CRYPT_OAEP, |
| cipherBuf, |
| &encryptSize, |
| maxOutLength)) { |
| |
| throw XSECCryptoException(XSECCryptoException::RSAError, |
| "WinCAPI:RSA publicKeyEncrypt - Error performing encrypt"); |
| } |
| |
| if (encryptSize <= 0) { |
| throw XSECCryptoException(XSECCryptoException::RSAError, |
| "WinCAPI:RSA publicKeyEncrypt - Error performing OAEP RSA encrypt"); |
| } |
| |
| break; |
| |
| default : |
| |
| throw XSECCryptoException(XSECCryptoException::RSAError, |
| "WinCAPI:RSA - Unknown padding method"); |
| } |
| |
| // Reverse the output |
| unsigned char *tbuf; |
| XSECnew(tbuf, unsigned char[encryptSize]); |
| ArrayJanitor<unsigned char> j_tbuf(tbuf); |
| memcpy(tbuf, cipherBuf, encryptSize); |
| |
| for (unsigned int i = 0; i < encryptSize; ++i) |
| cipherBuf[i] = tbuf[encryptSize - 1 - i]; |
| |
| return encryptSize; |
| } |
| |
| // -------------------------------------------------------------------------------- |
| // Size in bytes |
| // -------------------------------------------------------------------------------- |
| |
| unsigned int WinCAPICryptoKeyRSA::getLength() const { |
| |
| DWORD len; |
| DWORD pLen = 4; |
| |
| if (!CryptGetKeyParam(m_key, |
| KP_BLOCKLEN, |
| (BYTE *) &len, |
| &pLen, |
| 0)) { |
| throw XSECCryptoException(XSECCryptoException::RSAError, |
| "WinCAPI:RSA - Error determining key size"); |
| } |
| |
| return len / 8; |
| } |
| |
| // -------------------------------------------------------------------------------- |
| // Some utility functions |
| // -------------------------------------------------------------------------------- |
| |
| void WinCAPICryptoKeyRSA::loadParamsFromKey() { |
| |
| if (m_key == 0) { |
| |
| if (m_keySpec == 0) |
| return; |
| |
| // See of we can get the user key |
| if (!CryptGetUserKey(m_p, m_keySpec, &m_key)) |
| return; |
| } |
| |
| // Export key into a keyblob |
| BOOL fResult; |
| DWORD blobLen; |
| |
| fResult = CryptExportKey( |
| m_key, |
| 0, |
| PUBLICKEYBLOB, |
| 0, |
| NULL, |
| &blobLen); |
| |
| if (fResult == 0 || blobLen < 1) { |
| throw XSECCryptoException(XSECCryptoException::RSAError, |
| "WinCAPI:RSA - Error exporting public key"); |
| } |
| |
| BYTE * blob; |
| XSECnew(blob, BYTE[blobLen]); |
| ArrayJanitor<BYTE> j_blob(blob); |
| |
| fResult = CryptExportKey( |
| m_key, |
| 0, |
| PUBLICKEYBLOB, |
| 0, |
| blob, |
| &blobLen); |
| |
| if (fResult == 0 || blobLen < 1) { |
| throw XSECCryptoException(XSECCryptoException::RSAError, |
| "WinCAPI:RSA - Error exporting public key"); |
| } |
| |
| RSAPUBKEY * pk = (RSAPUBKEY *) ( blob + WINCAPI_BLOBHEADERLEN ); |
| DWORD keyLen = pk->bitlen / 8; |
| |
| // Copy the keys |
| |
| BYTE * i = (BYTE *) ( pk ); |
| i += WINCAPI_RSAPUBKEYLEN; |
| if (mp_modulus != NULL) |
| delete[] mp_modulus; |
| |
| m_modulusLen = keyLen; |
| XSECnew(mp_modulus, BYTE[m_modulusLen]); |
| memcpy(mp_modulus, i, m_modulusLen); |
| |
| // Take the simple way out |
| XSECnew(mp_exponent, BYTE[4]); |
| *((DWORD *) mp_exponent) = pk->pubexp; |
| |
| // Now cut any leading 0s (Windows is LE, so start least significant end) |
| |
| m_exponentLen = 3; |
| while (m_exponentLen > 0 && mp_exponent[m_exponentLen] == 0) |
| m_exponentLen--; |
| |
| m_exponentLen++; // Make it a length as apposed to an offset |
| } |
| |
| unsigned int WinCAPICryptoKeyRSA::getExponentBase64BigNums(char* b64, unsigned int len) { |
| |
| if (m_key == 0 && m_keySpec == 0 && mp_exponent == NULL) { |
| |
| return 0; // Nothing we can do |
| |
| } |
| |
| if (mp_exponent == NULL) { |
| |
| loadParamsFromKey(); |
| |
| } |
| |
| unsigned int bLen; |
| unsigned char * b = WinCAPICryptoProvider::WinBN2b64(mp_exponent, m_exponentLen, bLen); |
| if (bLen > len) |
| bLen = len; |
| memcpy(b64, b, bLen); |
| delete[] b; |
| |
| return bLen; |
| } |
| |
| unsigned int WinCAPICryptoKeyRSA::getModulusBase64BigNums(char* b64, unsigned int len) { |
| |
| if (m_key == 0 && m_keySpec == 0 && mp_modulus == NULL) { |
| |
| return 0; // Nothing we can do |
| |
| } |
| |
| if (mp_modulus == NULL) { |
| |
| loadParamsFromKey(); |
| |
| } |
| |
| unsigned int bLen; |
| unsigned char * b = WinCAPICryptoProvider::WinBN2b64(mp_modulus, m_modulusLen, bLen); |
| if (bLen > len) |
| bLen = len; |
| memcpy(b64, b, bLen); |
| delete[] b; |
| |
| return bLen; |
| } |
| |
| #endif /* WINCAPI */ |