【发布时间】:2016-10-09 15:10:56
【问题描述】:
使用 Microsoft CryptoAPI,我生成了一个新的 RSA 密钥对,现在正尝试将私钥导出到 PKCS#8 加密(受密码保护)PEM 文件。
我首先研究了CryptExportPKCS8()和CryptExportPKCS8Ex(),但是前者不支持加密密钥,后者是not exported by crypt32.dll。 MSDN 说这两个功能都已被弃用。
我目前的尝试是将从密码派生的会话密钥传递给 CryptExportKey():
HCRYPTPROV provider;
BOOL result = CryptAcquireContext(&provider, CONTAINER_NAME, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET | CRYPT_SILENT);
HCRYPTKEY keyPair;
result = CryptGenKey(provider, CALG_RSA_KEYX, (2048 << 16) | CRYPT_EXPORTABLE, &keyPair);
HCRYPTHASH hash;
result = CryptCreateHash(provider, CALG_SHA1, 0, 0, &hash);
const char *password = "password";
result = CryptHashData(hash, (const BYTE *)password, strlen(password), 0);
HCRYPTKEY sessionKey;
result = CryptDeriveKey(provider, CALG_3DES, hash, CRYPT_EXPORTABLE, &sessionKey);
DWORD blobSize;
result = CryptExportKey(keyPair, sessionKey, PRIVATEKEYBLOB, 0, NULL, &blobSize);
BYTE *blobBytes = new BYTE[blobSize];
result = CryptExportKey(keyPair, sessionKey, PRIVATEKEYBLOB, 0, blobBytes, &blobSize);
DWORD derSize;
// This throws "First-chance exception ... Access violation reading ..." and returns FALSE
result = CryptEncodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PKCS_RSA_PRIVATE_KEY, blobBytes, 0, NULL, NULL, &derSize);
// error is 3221225477 (0xC0000005)
DWORD error = GetLastError();
BYTE *derBytes = new BYTE[derSize];
result = CryptEncodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PKCS_RSA_PRIVATE_KEY, blobBytes, 0, NULL, derBytes, &derSize);
// ... CryptBinaryToString() to convert to PEM
// ... Write PEM to file
在注释掉的 CryptEncodeObjectEx() 之前,所有调用都会成功。
如果我不将会话密钥传递给 CryptExportKey(),那么我可以成功使用 CryptEncodeObjectEx() 对私钥进行编码,但显然它是纯文本的。
如何导出受密码保护的私钥?我派生会话密钥的方式有问题吗? PKCS_RSA_PRIVATE_KEY 是错误的编码类型吗?
我一直在 Windows 7 上的 Visual Studio 2013 中进行测试。
【问题讨论】:
标签: c++ winapi encryption cryptoapi