HCRYPTKEY WinCAPICryptoSymmetricKey::createWindowsKey()

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;

}