我试图使用Windows Crypto API生成RSA密钥对,然后以DER或PEM导出公共密钥。我的代码可以正常工作,并且可以成功导出 private 密钥,但是我还没有弄清楚如何使用公钥进行同样的操作。我的最终目标是将公钥提供给openssl以验证签名。
我已经看到了这个问题:Microsoft CryptoAPI: how to convert PUBLICKEYBLOB to DER/PEM?
但是我还没有找到解决方案。如何仅使用本机Windows Crypto API函数将公钥保存为有效的PEM格式?我想念什么?谢谢!
这是相关的代码段,我的API调用顺序要求我将 private 密钥导出为DER / PEM:
HCRYPTPROV hProv = NULL;
CryptAcquireContext(&hProv, NULL, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, 0)
HCRYPTKEY hPrivateKey = NULL;
CryptGenKey(hProv, AT_KEYEXCHANGE, CRYPT_ARCHIVABLE, &hPrivateKey);
CryptExportKey(hPrivateKey, 0, PRIVATEKEYBLOB, 0, 0, &size);
BYTE* pPrivKeyBlob = (BYTE *)malloc(size);
CryptExportKey(hPrivateKey, 0, PRIVATEKEYBLOB, 0, pPrivKeyBlob, &size);
CryptEncodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PKCS_RSA_PRIVATE_KEY, pPrivKeyBlob, 0, NULL, NULL, &size);
BYTE* pPrivDer = (BYTE *)malloc(size);
CryptEncodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PKCS_RSA_PRIVATE_KEY, pPrivKeyBlob, 0, NULL, pPrivDer, &size);
这有效,并且pPrivDer
包含DER格式的私钥。我可以将其格式化为PEM没问题:
DWORD pemSize = 0;
CryptBinaryToStringA(pPrivDer, size, CRYPT_STRING_BASE64HEADER, NULL, &pemSize);
LPSTR pPrivPEM = (LPSTR)malloc(pemSize);
CryptBinaryToStringA(pPrivDer, size, CRYPT_STRING_BASE64HEADER, pPrivPEM, &pemSize);
printf("%s", pPrivPEM);
这很好用,并且密钥的格式正确(更改标题可以使openssl读取/解析它)
但是,我终生无法弄清楚如何将公共密钥保存在DER / PEM中。这就是我正在尝试的:
//export public key
CryptExportKey(hPrivateKey, 0, PUBLICKEYBLOB, 0, 0, &size);
BYTE* pPubKeyBlob = (BYTE *)malloc(size);
CryptExportKey(hPrivateKey, 0, PUBLICKEYBLOB, 0, pPubKeyBlob, &size);
CryptEncodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, RSA_CSP_PUBLICKEYBLOB, mypubkey, 0, NULL, NULL, &size);
BYTE* pPubDer = (BYTE *)malloc(size);
CryptEncodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, RSA_CSP_PUBLICKEYBLOB, mypubkey, 0, NULL, pPubDer, &size);
DWORD pPubPEMSize = 0;
CryptBinaryToStringA(pPubDer, size, CRYPT_STRING_BASE64, NULL, &pPubPEMSize);
LPSTR pPubPEM = (LPSTR)malloc(pPubPEMSize);
CryptBinaryToStringA(pPubDer, size, CRYPT_STRING_BASE64, pPubPEM, &pPubPEMSize);
printf("-----BEGIN PUBLIC KEY-----\n%s-----END PUBLIC KEY-----\n\n", pPubPEM);
这不会导致任何错误,但是opensl无法识别导出的DER和公共密钥的已打印PEM,并且格式似乎错误。