如何导出从 CNG API 生成的 RSA 密钥?
How to export RSA Keys generated from CNG API?
我使用以下 CNG API 序列成功生成了 RSA 密钥:
BCryptOpenAlgorithmProvider(.., BCRYPT_RSA_ALGORITHM, ...);
BCryptGenerateKeyPair(..., 2048/*Key size*/, ...);
BCryptFinalizeKeyPair(...);
BCryptExportKey(..., BCRYPT_RSAPRIVATE_BLOB, ...);
BCryptExportKey(..., BCRYPT_RSAPUBLIC_BLOB, ...);
我对生成的缓冲区的哪一部分感到困惑,应该对其进行 Base64 编码以写出 PEM 文件?如果我对现有有效 PEM 文件所具有的整个缓冲区进行 Base64 编码,我在缓冲区中看不到 'MIIE'。
非常感谢任何指导。
确实不需要直接从 BCryptExportKey
或 NCryptExportKey
输出 base64 编码,但需要执行额外的步骤:
- 使用
BCryptExportKey
(或 NCryptExportKey
)
BCRYPT_RSAFULLPRIVATE_BLOB
(但不是 BCRYPT_RSAPRIVATE_BLOB
)或 BCRYPT_RSAPUBLIC_BLOB
- 对结果
BCRYPT_RSAKEY_BLOB
进行编码
CNG_RSA_PRIVATE_KEY_BLOB
或 CNG_RSA_PUBLIC_KEY_BLOB
并放入 CRYPT_PRIVATE_KEY_INFO
- 用
PKCS_PRIVATE_KEY_INFO
编码CRYPT_PRIVATE_KEY_INFO
- 致电
CryptBinaryToStringA
只有在这之后才会 'MIIE' 在缓冲区内
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;
}
并使用它:
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);
}
我使用以下 CNG API 序列成功生成了 RSA 密钥:
BCryptOpenAlgorithmProvider(.., BCRYPT_RSA_ALGORITHM, ...);
BCryptGenerateKeyPair(..., 2048/*Key size*/, ...);
BCryptFinalizeKeyPair(...);
BCryptExportKey(..., BCRYPT_RSAPRIVATE_BLOB, ...);
BCryptExportKey(..., BCRYPT_RSAPUBLIC_BLOB, ...);
我对生成的缓冲区的哪一部分感到困惑,应该对其进行 Base64 编码以写出 PEM 文件?如果我对现有有效 PEM 文件所具有的整个缓冲区进行 Base64 编码,我在缓冲区中看不到 'MIIE'。
非常感谢任何指导。
确实不需要直接从 BCryptExportKey
或 NCryptExportKey
输出 base64 编码,但需要执行额外的步骤:
- 使用
BCryptExportKey
(或NCryptExportKey
)BCRYPT_RSAFULLPRIVATE_BLOB
(但不是BCRYPT_RSAPRIVATE_BLOB
)或BCRYPT_RSAPUBLIC_BLOB
- 对结果
BCRYPT_RSAKEY_BLOB
进行编码CNG_RSA_PRIVATE_KEY_BLOB
或CNG_RSA_PUBLIC_KEY_BLOB
并放入CRYPT_PRIVATE_KEY_INFO
- 用
PKCS_PRIVATE_KEY_INFO
编码 - 致电
CryptBinaryToStringA
CRYPT_PRIVATE_KEY_INFO
只有在这之后才会 'MIIE' 在缓冲区内
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;
}
并使用它:
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);
}