in xsec/enc/WinCAPI/WinCAPICryptoSymmetricKey.cpp [620:753]
HCRYPTKEY WinCAPICryptoSymmetricKey::createWindowsKey(
const unsigned char * key,
unsigned int keyLen,
XSECCryptoSymmetricKey::SymmetricKeyType type,
HCRYPTPROV * prov) {
// First get the correct Provider handle to load the key into
HCRYPTPROV p;
if (prov == NULL || *prov == 0) {
if (!strEquals(XSECPlatformUtils::g_cryptoProvider->getProviderName(), DSIGConstants::s_unicodeStrPROVWinCAPI)) {
throw XSECCryptoException(XSECCryptoException::SymmetricError,
"WinCAPI:SymmetricKey - Main provider is not Windows provider");
}
WinCAPICryptoProvider * cp =
(WinCAPICryptoProvider*) XSECPlatformUtils::g_cryptoProvider;
p = cp->getApacheKeyStore();
if (p == 0) {
throw XSECCryptoException(XSECCryptoException::SymmetricError,
"WinCAPI:SymmetricKey - Unable to retrieve internal key store");
}
if (prov != NULL)
*prov = p;
}
else if (prov != NULL)
p = *prov;
// Get the key wrapping key
HCRYPTKEY k;
if (!CryptGetUserKey(p, AT_KEYEXCHANGE, &k)) {
throw XSECCryptoException(XSECCryptoException::SymmetricError,
"WinCAPI:SymmetricKey - Unable to retrieve internal key pair");
}
// Find out how long the output will be
DWORD outl = 0;
if (!CryptEncrypt(k, 0, TRUE, 0, 0, &outl, keyLen)) {
DWORD error = GetLastError();
if (error == NTE_BAD_KEY) {
// We throw either way, but this is *likely* to be an unsupported OS issue
throw XSECCryptoException(XSECCryptoException::SymmetricError,
"WinCAPI:SymmetricKey::createWindowsKey - Error encrypting a key - is this >= Windows 2000?");
}
throw XSECCryptoException(XSECCryptoException::SymmetricError,
"WinCAPI:SymmetricKey - Unable to determine space required to encrypt key");
}
// Create the necessary buffer
unsigned char * encryptBuf;
unsigned int encryptBufSize = outl;
XSECnew(encryptBuf, unsigned char[outl]);
ArrayJanitor<unsigned char> j_encryptBuf(encryptBuf);
memcpy(encryptBuf, key, keyLen);
outl = keyLen;
// Do the encrypt
if (!CryptEncrypt(k, 0, TRUE, 0, encryptBuf, &outl, encryptBufSize)) {
throw XSECCryptoException(XSECCryptoException::SymmetricError,
"WinCAPI:SymmetricKey - Unable to encrypt key");
}
// Now we have the encrypted buffer, create a SIMPLEBLOB structure
unsigned char * simpleBlob;
XSECnew(simpleBlob, unsigned char [sizeof (BLOBHEADER) + sizeof (DWORD) + outl]);
ArrayJanitor<unsigned char> j_simpleBlob(simpleBlob);
BLOBHEADER * blobHeader = (BLOBHEADER *) simpleBlob;
blobHeader->bType = SIMPLEBLOB;
blobHeader->bVersion = CUR_BLOB_VERSION;
blobHeader->reserved = 0;
unsigned int expectedLength;
switch (type) {
case (XSECCryptoSymmetricKey::KEY_3DES_192) :
blobHeader->aiKeyAlg = CALG_3DES;
expectedLength = 24;
break;
case (XSECCryptoSymmetricKey::KEY_AES_128) :
blobHeader->aiKeyAlg = CALG_AES_128;
expectedLength = 16;
break;
case (XSECCryptoSymmetricKey::KEY_AES_192) :
blobHeader->aiKeyAlg = CALG_AES_192;
expectedLength = 24;
break;
case (XSECCryptoSymmetricKey::KEY_AES_256) :
blobHeader->aiKeyAlg = CALG_AES_256;
expectedLength = 32;
break;
default :
throw XSECCryptoException(XSECCryptoException::SymmetricError,
"WinCAPI:SymmetricKey::createWindowsKey - Unknown Symmetric key type");
}
// Check key length - otherwise the user could get some very cryptic error messages
if (keyLen != expectedLength) {
throw XSECCryptoException(XSECCryptoException::SymmetricError,
"WinCAPI:SymmetricKey::createWindowsKey - Key length incorrect for algorithm");
}
DWORD * algId = (DWORD *) (simpleBlob + sizeof(BLOBHEADER));
*algId = CALG_RSA_KEYX;
// Copy in the encrypted data
memcpy(&simpleBlob[sizeof(BLOBHEADER) + sizeof(DWORD)], encryptBuf, outl);
// Now do the import
HCRYPTKEY k2;
if (!CryptImportKey(p, simpleBlob, sizeof(BLOBHEADER) + sizeof(DWORD) + outl, k, CRYPT_EXPORTABLE, &k2)) {
throw XSECCryptoException(XSECCryptoException::SymmetricError,
"WinCAPI:SymmetricKey - Unable to import key");
}
return k2;
}