I successfully generated RSA keys using the following sequence of CNG APIs:
BCryptOpenAlgorithmProvider(.., BCRYPT_RSA_ALGORITHM, ...);
BCryptGenerateKeyPair(..., 2048/*Key size*/, ...);
BCryptFinalizeKeyPair(...);
BCryptExportKey(..., BCRYPT_RSAPRIVATE_BLOB, ...);
BCryptExportKey(..., BCRYPT_RSAPUBLIC_BLOB, ...);
I'm confused though which part of the buffer generated, should be Base64 encoded to write out a PEM file? I'm not seeing 'MIIE' within the buffer if I Base64 encode the whole buffer that existing valid PEM files have.
Any guidance is greatly appreciated.
really need not direct base64 encode output from BCryptExportKey or NCryptExportKey but do extra steps:
BCryptExportKey (or NCryptExportKey) with
BCRYPT_RSAFULLPRIVATE_BLOB (but not BCRYPT_RSAPRIVATE_BLOB ) or BCRYPT_RSAPUBLIC_BLOBBCRYPT_RSAKEY_BLOB with
CNG_RSA_PRIVATE_KEY_BLOB or CNG_RSA_PUBLIC_KEY_BLOB and put to CRYPT_PRIVATE_KEY_INFOCRYPT_PRIVATE_KEY_INFO with PKCS_PRIVATE_KEY_INFOCryptBinaryToStringAonly after this will be 'MIIE' within the buffer
HRESULT bthr(BOOL b)
{
return b ? S_OK : HRESULT_FROM_WIN32(GetLastError());
}
HRESULT ExportToPem(_In_ BCRYPT_KEY_HANDLE hKey, BOOL bPrivate, _Out_ PSTR* ppsz, _Out_ PULONG pcch)
{
HRESULT hr;
CRYPT_PRIVATE_KEY_INFO PrivateKeyInfo = { 0, {const_cast<PSTR>(szOID_RSA_RSA)} };
ULONG cbKey = 0;
PUCHAR pbKey = 0;//really PBCRYPT_RSAKEY_BLOB
PCWSTR pszBlobType;
PCSTR lpszStructType;
if (bPrivate)
{
pszBlobType = BCRYPT_RSAFULLPRIVATE_BLOB;
lpszStructType = CNG_RSA_PRIVATE_KEY_BLOB;
}
else
{
pszBlobType = BCRYPT_RSAPUBLIC_BLOB;
lpszStructType = CNG_RSA_PUBLIC_KEY_BLOB;
}
while (0 <= (hr = BCryptExportKey(hKey, 0, pszBlobType, pbKey, cbKey, &cbKey, 0)))
{
if (pbKey)
{
if (0 <= (hr = bthr(CryptEncodeObjectEx(X509_ASN_ENCODING,
lpszStructType, pbKey, CRYPT_ENCODE_ALLOC_FLAG, 0,
&PrivateKeyInfo.PrivateKey.pbData, &PrivateKeyInfo.PrivateKey.cbData))))
{
hr = bthr(CryptEncodeObjectEx(X509_ASN_ENCODING, PKCS_PRIVATE_KEY_INFO,
&PrivateKeyInfo, CRYPT_ENCODE_ALLOC_FLAG, 0,
&pbKey, &cbKey));
LocalFree(PrivateKeyInfo.PrivateKey.pbData);
if (0 <= hr)
{
PSTR psz = 0;
ULONG cch = 0;
while (0 <= (hr = bthr(CryptBinaryToStringA(
pbKey, cbKey, CRYPT_STRING_BASE64, psz, &cch))))
{
if (psz)
{
*ppsz = psz, *pcch = cch;
break;
}
if (!(psz = (PSTR)LocalAlloc(0, cch)))
{
hr = HRESULT_FROM_WIN32(GetLastError());
break;
}
}
LocalFree(pbKey);
}
}
break;
}
pbKey = (PUCHAR)alloca(cbKey);
}
return hr;
}
and use it:
PSTR psz;
ULONG cch;
if (0 <= ExportToPem(hKey, bPrivate, &psz, &cch))
{
PSTR pc = psz;
ULONG cb;
do
{
cb = min(cch, 0x100);
DbgPrint("%.*s", cb, pc);
} while (pc += cb, cch -= cb);
LocalFree(psz);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With