9

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

2 に答える 2

10

あなたが説明する問題の理由は非常に簡単です。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_PROVMS_ENH_RSA_AES_PROV_XPます。

オペレーティングシステムのバージョンをテストしたくない場合は、CryptAcquireContextNULLasで使用できますpszProvider(引き続き as として使用PROV_RSA_AESしますdwProvType)。コードに を含めることができますanalyzeCryptographicSupport(NULL);

レジストリ キーの「名前」の値を調べることもできます。

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Defaults\Provider Types\Type 024

既定のPROV_RSA_AESプロバイダーの名前を表示します。

于 2010-12-23T23:44:56.460 に答える
0

Microsoft が名前をだましていて、「(Prototype)」が XP に存在し、Vista 以降に存在しない必要があることをどこかで読んだことを覚えていると思います。実行時にプラットフォームを検出し、適切な文字列を使用する必要があると思います。

于 2010-12-21T15:47:10.730 に答える