Загрузить файл PEM X509 в Windows CryptoApi - PullRequest
14 голосов
/ 05 августа 2009

Я новичок во всем, что касается Crypto, поэтому прошу несколько основных указателей.

Мне нужно загрузить .PEM (X509) "----- BEGIN RSA XXX KEY ----- ----- END RSA XXX KEY -----" в контекст Windows Crypto Api для использования с C ++ (я нашел примеры для Python и .NET, но они используют специальные функции, которые я не могу отнести к простой Windows Crypto Api)

Я понимаю, как зашифровать / расшифровать, когда у меня есть HCRYPTKEY. НО, я просто не понимаю, как импортировать BLOB-объект Base64 в файл (ы) .PEM и получить из него HCRYPTKEY, который я могу использовать.

У меня странное ощущение, что это нечто большее, чем просто вызов CryptDecodeObject ().

Какие-нибудь указатели, которые могут поставить меня на путь? Я уже потерял 2 дня, занимаясь программированием «методом проб и ошибок» и не получая ничего.

Ответы [ 3 ]

20 голосов
/ 27 сентября 2010

KJKHyperion сказал в своем ответе :

Я обнаружил «волшебную» последовательность вызовов для импорта открытого ключа RSA в формате PEM. Вот, пожалуйста:

  1. декодировать ключ в двоичный двоичный объект с помощью CryptStringToBinary ; pass CRYPT_STRING_BASE64HEADER в dwFlags
  2. декодировать двоичный двоичный ключ в CERT_PUBLIC_KEY_INFO с помощью CryptDecodeObjectEx ; передать X509_ASN_ENCODING в dwCertEncodingType и X509_PUBLIC_KEY_INFO в lpszStructType
  3. декодировать BLOB-объект PublicKey из CERT_PUBLIC_KEY_INFO в ключевой BLOB-объект RSA с помощью CryptDecodeObjectEx ; передать X509_ASN_ENCODING в dwCertEncodingType и RSA_CSP_PUBLICKEYBLOB в lpszStructType
  4. импорт ключевого объекта RSA с помощью CryptImportKey

Эта последовательность действительно помогла мне понять, что происходит, но она не работала для меня как есть. Второй звонок CryptDecodeObjectEx дал мне ошибку: Msgstr "встречено неверное значение тега ASN.1". После многих попыток понять документацию Microsoft я наконец понял, что вывод первого декодера не может быть снова декодирован как ASN, и что он фактически готов к импорту. С этим пониманием я нашел ответ по следующей ссылке:

http://www.ms -news.net / f2748 / проблема импортирующего-открытый ключ-4052577.html

Ниже приведена моя собственная программа, которая импортирует открытый ключ из файла .pem в контекст CryptApi:

int main()
{
    char           pemPubKey[2048];
    int            readLen;
    char           derPubKey[2048];
    size_t         derPubKeyLen = 2048;
    CERT_PUBLIC_KEY_INFO *publicKeyInfo;
    int            publicKeyInfoLen;
    HANDLE         hFile;
    HCRYPTPROV     hProv = 0;
    HCRYPTKEY      hKey = 0;

    /*
     * Read the public key cert from the file
     */
    hFile = CreateFileA( "c:\\pub.pem", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
    if ( hFile == INVALID_HANDLE_VALUE )
    {
        fprintf( stderr, "Failed to open file. error: %d\n", GetLastError() );
    }

    if ( !ReadFile( hFile, pemPubKey, 2048, &readLen, NULL ) )
    {
        fprintf( stderr, "Failed to read file. error: %d\n", GetLastError() );
    }

    /*
     * Convert from PEM format to DER format - removes header and footer and decodes from base64
     */
    if ( !CryptStringToBinaryA( pemPubKey, 0, CRYPT_STRING_BASE64HEADER, derPubKey, &derPubKeyLen, NULL, NULL ) )
    {
        fprintf( stderr, "CryptStringToBinary failed. Err: %d\n", GetLastError() );
    }

    /*
     * Decode from DER format to CERT_PUBLIC_KEY_INFO
     */
    if ( !CryptDecodeObjectEx( X509_ASN_ENCODING, X509_PUBLIC_KEY_INFO, derPubKey, derPubKeyLen, 
                               CRYPT_ENCODE_ALLOC_FLAG, NULL, &publicKeyInfo, &publicKeyInfoLen ) )
    {
        fprintf( stderr, "CryptDecodeObjectEx 1 failed. Err: %p\n", GetLastError() );
        return -1;
    }

    /*
     * Acquire context 
     */
    if( !CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) )
    {
        {
            printf( "CryptAcquireContext failed - err=0x%x.\n", GetLastError() );
            return -1;
        }
    }

    /*
     * Import the public key using the context
     */
    if ( !CryptImportPublicKeyInfo( hProv, X509_ASN_ENCODING, publicKeyInfo, &hKey ) )
    {
        fprintf( stderr, "CryptImportPublicKeyInfo failed. error: %d\n", GetLastError() );
        return -1;
    }
    LocalFree( publicKeyInfo );

    /*
     * Now use hKey to encrypt whatever you need.
     */

    return 0;
}
10 голосов
/ 14 января 2010

Я обнаружил «волшебную» последовательность вызовов для импорта открытого ключа RSA в формате PEM. Вот, пожалуйста:

  1. декодировать ключ в двоичный двоичный объект с помощью CryptStringToBinary ; передать CRYPT_STRING_BASE64HEADER в dwFlags
  2. декодировать двоичный двоичный ключ в CERT_PUBLIC_KEY_INFO с помощью CryptDecodeObjectEx ; передать X509_ASN_ENCODING в dwCertEncodingType и X509_PUBLIC_KEY_INFO в lpszStructType
  3. декодирует BLOB-объект PublicKey из CERT_PUBLIC_KEY_INFO в ключевой BLOB-объект RSA с помощью CryptDecodeObjectEx ; передайте X509_ASN_ENCODING в dwCertEncodingType и RSA_CSP_PUBLICKEYBLOB в lpszStructType
  4. импортировать блок ключей RSA с помощью CryptImportKey
2 голосов
/ 26 августа 2009

У меня сейчас такая же сложность. Я еще не закончил кодировать решение, но, насколько я понимаю, вам нужно удалить теги ----- BEGIN и т. Д. ----- и ----- END и т. Д. ------ и декодировать Base64 .

Это оставляет вам строку в кодировке DER, которую вам нужно проанализировать, чтобы получить модуль и открытый показатель. Из них вы можете заполнить структуры PUBLICKEYSTRUC и RSAPUBKEY. Удачи; -)

...