in azure-protected-vm-secrets/Windows/BcryptECDiffieHellman.cpp [321:562]
std::vector<unsigned char> BcryptECDiffieHellman::ExportPkcs8PrivateKey() const
{
std::vector<unsigned char> result;
#ifndef PLATFORM_UNIX
DWORD privateKeyBlobLen = 0;
NTSTATUS status;
CRYPT_ECC_PRIVATE_KEY_INFO eccPrivateInfo = { 0 };
CRYPT_PRIVATE_KEY_INFO* privateKeyInfo = nullptr;
DWORD privateKeyInfoLen = 0;
BYTE* pbCurveParameters = nullptr;
DWORD cbCurveParameters = 0;
BCRYPT_ECCKEY_BLOB* pekb = nullptr;
// Get the size of the private key blob
status = BCryptExportKey(this->hEccKeyHandle, NULL, BCRYPT_ECCPRIVATE_BLOB, NULL, 0, &privateKeyBlobLen, 0);
if (status != STATUS_SUCCESS) {
// LibraryError, Bcrypt subclass, keyError
throw BcryptError(status, "BCryptExportKey - Get Size - failed.\n",
ErrorCode::LibraryError_Bcrypt_keyError);
}
unsigned char* privateKeyBlob = (unsigned char *)malloc(privateKeyBlobLen);
// Export the private key blob
status = BCryptExportKey(this->hEccKeyHandle, NULL, BCRYPT_ECCPRIVATE_BLOB, privateKeyBlob, privateKeyBlobLen, &privateKeyBlobLen, 0);
if (status != STATUS_SUCCESS) {
// LibraryError, Bcrypt subclass, keyError
throw BcryptError(status, "BCryptExportKey - Export Key - failed.\n",
ErrorCode::LibraryError_Bcrypt_keyError);
}
pekb = (BCRYPT_ECCKEY_BLOB*)privateKeyBlob;
// Get the size of the curve parameters
status = BCryptGetProperty(
this->hEccKeyHandle,
BCRYPT_ECC_PARAMETERS,
NULL, // pbOutput
0, // cbOutput
&cbCurveParameters,
0 // dwFlags
);
if (status != STATUS_SUCCESS) {
// LibraryError, Bcrypt subclass, propertyError
throw BcryptError(status, "BCryptGetProperty Size failed.\n",
ErrorCode::LibraryError_Bcrypt_propertyError);
}
// Get the curve parameters
pbCurveParameters = (BYTE*)malloc(cbCurveParameters);
status = BCryptGetProperty(
this->hEccKeyHandle,
BCRYPT_ECC_PARAMETERS,
pbCurveParameters,
cbCurveParameters,
&cbCurveParameters,
0);
if (status != STATUS_SUCCESS) {
// LibraryError, Bcrypt subclass, propertyError
throw BcryptError(status, "BCryptGetProperty Value failed.\n",
ErrorCode::LibraryError_Bcrypt_propertyError);
}
CRYPT_DATA_BLOB CNGECCBlob = { 0 };
CNGECCBlob.cbData = cbCurveParameters;
CNGECCBlob.pbData = pbCurveParameters;
ULONG cbCurveInfo = 0;
// Get the size of the curve info
if (!CryptEncodeObject(
X509_ASN_ENCODING,
X509_ECC_PARAMETERS,
&CNGECCBlob,
NULL,
&cbCurveInfo))
{
// ParsingError, ASN subclass, x509PrivKeyError
throw WinCryptError("CryptEncodeObject 1 failed.", GetLastError(),
ErrorCode::ParsingError_Asn1_x509PrivKeyError);
}
eccPrivateInfo.dwVersion = CRYPT_ECC_PRIVATE_KEY_INFO_v1;
eccPrivateInfo.szCurveOid = NULL;
eccPrivateInfo.PrivateKey.pbData = (BYTE*)(pekb + 1) + EC_PUBLIC_NUM_COMPONENTS * pekb->cbKey;
eccPrivateInfo.PrivateKey.cbData = pekb->cbKey;
ULONG cbPublicKey;
BYTE* pbPublicKey;
pbPublicKey = (BYTE*)&pekb[1];
cbPublicKey = pekb->cbKey;
eccPrivateInfo.PublicKey.cbData = 1 + 2 * cbPublicKey;
eccPrivateInfo.PublicKey.cUnusedBits = 0;
eccPrivateInfo.PublicKey.pbData = (BYTE*)malloc(eccPrivateInfo.PublicKey.cbData);
ZeroMemory(eccPrivateInfo.PublicKey.pbData, eccPrivateInfo.PublicKey.cbData);
eccPrivateInfo.PublicKey.pbData[0] = EC_UNCOMPRESSED_BLOB;
CopyMemory(
eccPrivateInfo.PublicKey.pbData + 1,
pbPublicKey,
cbPublicKey);
CopyMemory(
eccPrivateInfo.PublicKey.pbData + 1 + cbPublicKey,
pbPublicKey + pekb->cbKey,
cbPublicKey);
CRYPT_BIT_BLOB CryptBitBlob = { 0 };
CryptBitBlob.cbData = 1;
CryptBitBlob.pbData = (BYTE*)malloc(1);
CryptBitBlob.pbData[0] = CERT_KEY_AGREEMENT_KEY_USAGE;
CryptBitBlob.cUnusedBits = 0;
ULONG cbKeyUsage = 0;
ULONG cbEncodedKey = 0;
// Get the size of the key
if (!CryptEncodeObjectEx(
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
X509_ECC_PRIVATE_KEY,
(BYTE*)(&eccPrivateInfo),
0,
NULL,
NULL, &cbEncodedKey))
{
// ParsingError, ASN subclass, x509PrivKeyError
throw WinCryptError("CryptEncodeObjectEx 1 failed.", GetLastError(),
ErrorCode::ParsingError_Asn1_x509PrivKeyError);
}
ULONG cbPriKeyInfo = cbPriKeyInfo = sizeof(*privateKeyInfo) + sizeof(szOID_ECC_PUBLIC_KEY);
if (cbKeyUsage > 0)
{
cbPriKeyInfo +=
sizeof(CRYPT_ATTRIBUTES) +
sizeof(CRYPT_ATTRIBUTE) +
sizeof(CRYPT_ATTR_BLOB) +
sizeof(szOID_KEY_USAGE);
}
cbPriKeyInfo += cbCurveInfo;
cbPriKeyInfo += cbKeyUsage;
cbPriKeyInfo += cbEncodedKey;
BYTE* pb = NULL;
privateKeyInfo = (PCRYPT_PRIVATE_KEY_INFO)malloc(cbPriKeyInfo);
if (privateKeyInfo == NULL) {
// GenericError, Memory subclass, mallocError
throw std::exception("ECDH Malloc Fail");
}
ZeroMemory(privateKeyInfo, cbPriKeyInfo);
if (cbKeyUsage > 0)
{
CRYPT_ATTRIBUTES* pAttrList = (CRYPT_ATTRIBUTES*)(privateKeyInfo + 1);
CRYPT_ATTRIBUTE* pAttr = (CRYPT_ATTRIBUTE*)(pAttrList + 1);
CRYPT_ATTR_BLOB* pAttrBlob = (CRYPT_ATTR_BLOB*)(pAttr + 1);
privateKeyInfo->pAttributes = pAttrList;
pAttrList->cAttr = 1;
pAttrList->rgAttr = pAttr;
pAttr->pszObjId = (PSTR)(pAttrBlob + 1);
pAttr->cValue = 1;
pAttr->rgValue = pAttrBlob;
pAttrBlob->cbData = cbKeyUsage;
pAttrBlob->pbData =
(BYTE*)(pAttr->pszObjId + sizeof(szOID_KEY_USAGE));
CopyMemory(
pAttr->pszObjId,
szOID_KEY_USAGE,
sizeof(szOID_KEY_USAGE));
if (!CryptEncodeObject(
X509_ASN_ENCODING,
X509_BITS,
&CryptBitBlob,
pAttrBlob->pbData,
&pAttrBlob->cbData))
{
// ParsingError, ASN subclass, x509PrivKeyError
throw WinCryptError("CryptEncodeObjectEx 2 failed.", GetLastError(),
ErrorCode::ParsingError_Asn1_x509PrivKeyError);
}
pb = pAttrBlob->pbData + pAttrBlob->cbData;
}
else
{
pb = (BYTE*)(privateKeyInfo + 1);
}
privateKeyInfo->Algorithm.Parameters.cbData = cbCurveInfo;
privateKeyInfo->Algorithm.Parameters.pbData = pb + cbEncodedKey;
privateKeyInfo->Algorithm.pszObjId =
(PSTR)(pb + cbEncodedKey + cbCurveInfo);
privateKeyInfo->PrivateKey.cbData = cbEncodedKey;
privateKeyInfo->PrivateKey.pbData = pb;
// Encode the key
if (!CryptEncodeObjectEx(
X509_ASN_ENCODING,
X509_ECC_PRIVATE_KEY,
&eccPrivateInfo,
0,
NULL,
privateKeyInfo->PrivateKey.pbData,
&privateKeyInfo->PrivateKey.cbData))
{
// ParsingError, ASN subclass, x509PrivKeyError
throw WinCryptError("CryptEncodeObjectEx 3 failed.", GetLastError(),
ErrorCode::ParsingError_Asn1_x509PrivKeyError);
}
// Encode the curve parameters
if (!CryptEncodeObject(
X509_ASN_ENCODING,
X509_ECC_PARAMETERS,
&CNGECCBlob,
privateKeyInfo->Algorithm.Parameters.pbData,
&privateKeyInfo->Algorithm.Parameters.cbData))
{
// ParsingError, ASN subclass, x509PrivKeyError
throw WinCryptError("CryptEncodeObjectEx 4 failed.", GetLastError(),
ErrorCode::ParsingError_Asn1_x509PrivKeyError);
}
CopyMemory(
privateKeyInfo->Algorithm.pszObjId,
szOID_ECC_PUBLIC_KEY,
sizeof(szOID_ECC_PUBLIC_KEY));
ULONG derPrivateBytesLen = 0;
unsigned char *derPrivateBytes = nullptr;
// Encode the private key
if (!CryptEncodeObjectEx(
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
PKCS_PRIVATE_KEY_INFO,
(BYTE*)privateKeyInfo,
CRYPT_ENCODE_ALLOC_FLAG,
NULL,
&derPrivateBytes, &derPrivateBytesLen))
{
// ParsingError, ASN subclass, x509PrivKeyError
throw WinCryptError("CryptEncodeObjectEx 5 failed.", GetLastError(),
ErrorCode::ParsingError_Asn1_x509PrivKeyError);
}
result = std::vector<unsigned char>(derPrivateBytes, derPrivateBytes + derPrivateBytesLen);
#endif // !PLATFORM_UNIX
return result;
}