我正在尝试了解如何在XP,Vista和Windows 7中获取从PEM格式导入的公钥(下面的代码中包含的示例)。示例代码将在XP和Windows Vista / 7上导入密钥,但不一样。
在Windows XP上,加密提供程序的名称中需要字符串“(Prototype)”,并允许调用CryptImportPublicKeyInfo来传递。
在Windows 7上,“(Prototype)”提供程序显然存在,但不支持对CryptImportPublicKeyInfo的调用,这会令人困惑。
这些操作系统之间的正确实现是什么样的?是否有必要检测XP并使用“(Prototype)”请求名称,而没有它用于其他操作系统?是否有可能在某些XP系统上仍会失败?
或者,有没有办法检测这种令人困惑的行为,并选择哪个加密提供商支持必要的呼叫?
Windows 7上的输出:
ANALYZING CRYPTOGRAPHIC SUPPORT FOR:
"Microsoft Enhanced RSA and AES Cryptographic Provider"
CryptAcquireContext success.
CryptAcquireContext.1 success.
CryptStringToBinary.2 success.
CryptDecodeObjectEx success.
CryptImportPublicKeyInfo success.
SUCCESS.
ANALYZING CRYPTOGRAPHIC SUPPORT FOR:
"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
CryptAcquireContext success.
CryptAcquireContext.1 success.
CryptStringToBinary.2 success.
CryptDecodeObjectEx success.
CryptImportPublicKeyInfo FAILED****.
Windows XP上的输出:
ANALYZING CRYPTOGRAPHIC SUPPORT FOR:
"Microsoft Enhanced RSA and AES Cryptographic Provider"
CryptAcquireContext success.
CryptAcquireContext.1 success.
CryptStringToBinary.2 success.
CryptDecodeObjectEx success.
CryptImportPublicKeyInfo FAILED****.
ANALYZING CRYPTOGRAPHIC SUPPORT FOR:
"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
CryptAcquireContext success.
CryptAcquireContext.1 success.
CryptStringToBinary.2 success.
CryptDecodeObjectEx success.
CryptImportPublicKeyInfo success.
SUCCESS.
产生该输出的C ++源代码:(需要crypt32.lib)
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <wincrypt.h>
bool windowsAcquireProviderContext(HCRYPTPROV *pHandleProv, LPCTSTR pProviderName);
bool analyzeCryptographicSupport(LPCTSTR pProviderName);
int _tmain(int argc, _TCHAR* argv[])
{
analyzeCryptographicSupport(MS_ENH_RSA_AES_PROV);
analyzeCryptographicSupport(L"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)");
return 0;
}
bool windowsAcquireProviderContext(HCRYPTPROV *pHandleProv, LPCTSTR pProviderName) {
WCHAR *pContainerName = L"blah blah blah";
if(!CryptAcquireContext(pHandleProv, pContainerName, pProviderName, PROV_RSA_AES, CRYPT_SILENT)) {
if(GetLastError() == NTE_BAD_KEYSET) {
if(CryptAcquireContext(pHandleProv, pContainerName, pProviderName, PROV_RSA_AES, CRYPT_NEWKEYSET|CRYPT_SILENT)) {
return true;
}
}
}
return true;
}
LPCWSTR pwszPemPublicKey =
L"-----BEGIN PUBLIC KEY-----\r\n"
L"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC6GUVcbn92bahlwOskKi8XkG9q\r\n"
L"Vq863+C4cOWC6HzJojc011pJFFIBu8/pG1EI8FZJdBmTrFaJTriYw1/SpbOH0QqE\r\n"
L"eHanT8qWn+S5m9xgDJoWTBJKcnu3OHOvJJU3c8jOHQQnRWLfghJH4vnwStdiwUUY\r\n"
L"SMWpwuHObsNelGBgEQIDAQAB\r\n"
L"-----END PUBLIC KEY-----\r\n";
int pemPublicKeySize = wcslen(pwszPemPublicKey);
bool analyzeCryptographicSupport(LPCTSTR pProviderName) {
printf("ANALYZING CRYPTOGRAPHIC SUPPORT FOR:\r\n");
wprintf(L"\t \"%s\"\r\n", pProviderName);
HCRYPTPROV hProv;
if(!windowsAcquireProviderContext(&hProv, pProviderName)) {
wprintf(L"\t CryptAcquireContext FAILED.\r\n");
return false;
}
wprintf(L"\t CryptAcquireContext success.\r\n");
DWORD blobSize;
if(!CryptStringToBinary(pwszPemPublicKey, pemPublicKeySize, CRYPT_STRING_BASE64_ANY, NULL, &blobSize, NULL, NULL)) {
CryptReleaseContext(hProv, 0);
wprintf(L"\t CryptStringToBinary.1 FAILED****.\r\n");
return false;
}
wprintf(L"\t CryptAcquireContext.1 success.\r\n");
BYTE *pBlob = (BYTE *)malloc(blobSize);
if(!CryptStringToBinary(pwszPemPublicKey, pemPublicKeySize, CRYPT_STRING_BASE64_ANY, pBlob, &blobSize, NULL, NULL)) {
free(pBlob);
CryptReleaseContext(hProv, 0);
wprintf(L"\t CryptStringToBinary.2 FAILED****.\r\n");
return false;
}
wprintf(L"\t CryptStringToBinary.2 success.\r\n");
CERT_PUBLIC_KEY_INFO *publicKeyInfo;
DWORD publicKeyInfoLen;
HCRYPTKEY hPublicKey;
if(!CryptDecodeObjectEx(X509_ASN_ENCODING|PKCS_7_ASN_ENCODING, X509_PUBLIC_KEY_INFO, pBlob, blobSize, CRYPT_DECODE_ALLOC_FLAG, NULL, &publicKeyInfo, &publicKeyInfoLen)) {
free(pBlob);
CryptReleaseContext(hProv, 0);
wprintf(L"\t CryptDecodeObjectEx FAILED****.\r\n");
return false;
}
wprintf(L"\t CryptDecodeObjectEx success.\r\n");
if(!CryptImportPublicKeyInfo(hProv, X509_ASN_ENCODING|PKCS_7_ASN_ENCODING, publicKeyInfo, &hPublicKey)) {
LocalFree(publicKeyInfo);
free(pBlob);
CryptReleaseContext(hProv, 0);
wprintf(L"\t CryptImportPublicKeyInfo FAILED****.\r\n");
return false;
}
wprintf(L"\t CryptImportPublicKeyInfo success.\r\n");
CryptDestroyKey(hPublicKey);
LocalFree(publicKeyInfo);
free(pBlob);
CryptReleaseContext(hProv, 0);
wprintf(L"\t SUCCESS.\r\n");
return true;
}
答案 0 :(得分:10)
您描述的问题的原因非常简单: Microsoft从
重命名为AES加密提供程序"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
"Microsoft Enhanced RSA and AES Cryptographic Provider"
。 在WinCrypt.h
中定义了相应的常量,您可以使用MS_ENH_RSA_AES_PROV
和MS_ENH_RSA_AES_PROV_XP
。
如果您不想测试操作系统的版本,可以CryptAcquireContext使用NULL
作为pszProvider
(并继续使用PROV_RSA_AES
作为dwProvType
)。在您的代码中,您可以添加analyzeCryptographicSupport(NULL);
。
您还可以检查注册表项的“名称”值
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Defaults\Provider Types\Type 024
查看默认PROV_RSA_AES
提供商的名称。
答案 1 :(得分:0)
我想我记得在某个地方看到微软对这个名字进行了抨击,它要求“(Prototype)”出现在XP上并且不存在于Vista及以上版本中。我认为你必须在运行时检测平台并使用适当的字符串。