将X509 PEM文件加载到Windows CryptoApi中

时间:2009-08-05 04:24:09

标签: c++ windows cryptography cryptoapi pem

我是整个Crypto的新手,所以我求一些基本的指示。

我需要加载.PEM(X509)“----- BEGIN RSA XXX KEY ----- ----- END RSA XXX KEY -----”进入Windows Crypto Api上下文使用使用C ++(我找到了Python和.NET的示例,但它们使用了我无法与普通Windows Crypto Api相关的特定函数)

我知道如果我有HCRYPTKEY后如何加密/解密。 但是,我只是不知道如何在.PEM文件中导入Base64 blob并获得我可以使用的HCRYPTKEY。

我有这种感觉,除了简单地调用CryptDecodeObject()之外还有更多内容。

任何可以让我走上正轨的指针?我已经失去了2天做“试验和错误”编程而无处可去。

3 个答案:

答案 0 :(得分:20)

KJKHyperionanswer

中说
  

我发现以PEM格式导入RSA公钥的“神奇”调用序列。你走了:

     
      
  1. 使用 CryptStringToBinary 将密钥解码为二进制blob;在dwFlags中传递 CRYPT_STRING_BASE64HEADER
  2.   
  3. 使用 CryptDecodeObjectEx 将二进制密钥blob解码为CERT_PUBLIC_KEY_INFO;在dwCertEncodingType中传递X509_ASN_ENCODING,在lpszStructType中传递 X509_PUBLIC_KEY_INFO
  4.   
  5. 使用 CryptDecodeObjectEx 将PublicKey blob从CERT_PUBLIC_KEY_INFO解码为RSA密钥blob;在dwCertEncodingType中传递X509_ASN_ENCODING,在lpszStructType中传递 RSA_CSP_PUBLICKEYBLOB
  6.   
  7. 使用 CryptImportKey
  8. 导入RSA密钥blob   

这个序列确实帮助我理解了发生了什么,但它对我来说并不适用。第二次调用CryptDecodeObjectEx给了我一个错误: “符合ASN.1标签值”。 在多次尝试理解Microsoft文档之后,我终于意识到第一个解码的输出不能再被解码为ASN,并且它实际上已准备好导入。通过这种理解,我在以下链接中找到了答案:

http://www.ms-news.net/f2748/problem-importing-public-key-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;
}

答案 1 :(得分:10)

我发现以PEM格式导入RSA公钥的“神奇”调用序列。你走了:

  1. 使用 CryptStringToBinary 将密钥解码为二进制blob;在dwFlags中传递 CRYPT_STRING_BASE64HEADER
  2. 使用 CryptDecodeObjectEx 将二进制密钥blob解码为CERT_PUBLIC_KEY_INFO;在dwCertEncodingType中传递X509_ASN_ENCODING,在lpszStructType中传递 X509_PUBLIC_KEY_INFO
  3. 使用 CryptDecodeObjectEx 将PublicKey blob从CERT_PUBLIC_KEY_INFO解码为RSA密钥blob;在dwCertEncodingType中传递X509_ASN_ENCODING,在lpszStructType中传递 RSA_CSP_PUBLICKEYBLOB
  4. 使用 CryptImportKey
  5. 导入RSA密钥blob

答案 2 :(得分:2)

我目前面临同样的困难。我还没有完成解决方案的编码,但据我了解你需要剥离----- BEGIN等-----和----- END等------标记和解码Base64

这会留下DER编码的字符串,您需要解析该字符串以获得模数和公共指数。从那些你可以填充PUBLICKEYSTRUC和RSAPUBKEY结构。祝你好运; - )