Поведение MS Crypto API в Windows XP против Vista/7
Я пытаюсь понять, как получить открытый ключ, импортированный из формата PEM (пример включен в код ниже) через XP, Vista и Windows 7. Пример кода импортирует ключ как на XP, так и на Windows Vista/7, но не одинаково.
в Windows XP строка "(прототип)" требуется в имени поставщика криптографии и позволяет передавать вызов CryptImportPublicKeyInfo.
в Windows 7 "(прототип)" поставщик, по-видимому, присутствует, но не поддерживает вызов CryptImportPublicKeyInfo, что сбивает с толку.
как может выглядеть правильная реализация между этими операционными системами? Необходимо ли обнаружить XP и запросить имя с помощью "(прототип)", и без него для других операционных систем? Возможно ли, что это все равно не удастся на некоторых системах 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-----rn"
L"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC6GUVcbn92bahlwOskKi8XkG9qrn"
L"Vq863+C4cOWC6HzJojc011pJFFIBu8/pG1EI8FZJdBmTrFaJTriYw1/SpbOH0QqErn"
L"eHanT8qWn+S5m9xgDJoWTBJKcnu3OHOvJJU3c8jOHQQnRWLfghJH4vnwStdiwUUYrn"
L"SMWpwuHObsNelGBgEQIDAQABrn"
L"-----END PUBLIC KEY-----rn";
int pemPublicKeySize = wcslen(pwszPemPublicKey);
bool analyzeCryptographicSupport(LPCTSTR pProviderName) {
printf("ANALYZING CRYPTOGRAPHIC SUPPORT FOR:rn");
wprintf(L"t "%s"rn", pProviderName);
HCRYPTPROV hProv;
if(!windowsAcquireProviderContext(&hProv, pProviderName)) {
wprintf(L"t CryptAcquireContext FAILED.rn");
return false;
}
wprintf(L"t CryptAcquireContext success.rn");
DWORD blobSize;
if(!CryptStringToBinary(pwszPemPublicKey, pemPublicKeySize, CRYPT_STRING_BASE64_ANY, NULL, &blobSize, NULL, NULL)) {
CryptReleaseContext(hProv, 0);
wprintf(L"t CryptStringToBinary.1 FAILED****.rn");
return false;
}
wprintf(L"t CryptAcquireContext.1 success.rn");
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****.rn");
return false;
}
wprintf(L"t CryptStringToBinary.2 success.rn");
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****.rn");
return false;
}
wprintf(L"t CryptDecodeObjectEx success.rn");
if(!CryptImportPublicKeyInfo(hProv, X509_ASN_ENCODING|PKCS_7_ASN_ENCODING, publicKeyInfo, &hPublicKey)) {
LocalFree(publicKeyInfo);
free(pBlob);
CryptReleaseContext(hProv, 0);
wprintf(L"t CryptImportPublicKeyInfo FAILED****.rn");
return false;
}
wprintf(L"t CryptImportPublicKeyInfo success.rn");
CryptDestroyKey(hPublicKey);
LocalFree(publicKeyInfo);
free(pBlob);
CryptReleaseContext(hProv, 0);
wprintf(L"t SUCCESS.rn");
return true;
}
2 ответов
причина проблемы, которую вы описываете, очень проста:Microsoft переименовала поставщика шифрования AES С
-
"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
в Windows XP до -
"Microsoft Enhanced RSA and AES Cryptographic Provider"
в более поздних версиях операционных систем.
на WinCrypt.h
определены соответствующие константы как MS_ENH_RSA_AES_PROV
и MS_ENH_RSA_AES_PROV_XP
, который вы можете использовать.
если вы не хотите, чтобы проверить версию операционной системы, вы можете просто использовать CryptAcquireContext С NULL
as pszProvider
(и продолжают использовать PROV_RSA_AES
как dwProvType
). В свой код вы можете включить analyzeCryptographicSupport(NULL);
.
вы также можете проверить значение " имя " раздела реестра
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Defaults\Provider Types\Type 024
чтобы увидеть имя по умолчанию PROV_RSA_AES
провайдер.
кажется, я где-то читал, что Microsoft облажалась с именем, и для этого требуется "(прототип)" присутствовать на XP и отсутствовать на Vista и выше. Я думаю, вам придется обнаружить платформу во время выполнения и использовать соответствующую строку.