c++ - Windows XP 与 Vista/7 上的 MS Crypto API 行为

标签 c++ windows-xp cryptoapi mscapi

我正在尝试了解如何在 XP、Vista 和 Windows 7 中获取从 PEM 格式(示例包含在下面的代码中)导入的公钥。示例代码将在 XP 和 Windows Vista/7 上导入 key , 但方式不同。

在 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;
}

最佳答案

你描述的问题原因很简单:Microsoft renamed AES Cryptographic Provider from

  • Windows XP 中的“Microsoft 增强型 RSA 和 AES 加密提供程序(原型(prototype))”
  • “Microsoft Enhanced RSA and AES Cryptographic Provider” 在更高版本的操作系统中。

WinCrypt.h 中定义了相应的常量作为 MS_ENH_RSA_AES_PROVMS_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 提供商的名称。

关于c++ - Windows XP 与 Vista/7 上的 MS Crypto API 行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4495247/

相关文章:

c++ - 模板类型名作为同一模板的其他参数的类型

java - 加载 keystore 时如何防止弹出窗口

linux - Ciphertext-Policy Attribute-Based Encryption toolkit "make"错误与 libgmp

c - 如何使用自定义加密服务提供商 (CSP) 在 Chrome 上进行 SSL/TLS 客户端身份验证

c++ - 检测到堆栈粉碎,中止,OpenGl freeglut

c++ - 创建动态大小的对象

c++ - 我如何围绕概念和不完整类型的限制进行设计?

c - 为什么我的所有者数据 ListView 状态图像在 Windows XP 上显示为空白?

c++ - Win32 应用程序在最小化窗口动画时挂起

c++ Interlocked Ops 在 WinXP 上