8

我正在尝试开发许可证验证解决方案。RSA_private_encrypt使用 OpenSSL 的功能在服务器上对许可证进行编码。

对于 Mac OX XI 使用RSA_public_decrypt,它就像一个魅力。在 Windows 上,我必须使用非常少的代码,所以我不能与 OpenSSL 或其他库链接,我必须使用 MS Crypto API。

我花了几天时间试图找出问题所在,但没有运气。我可以成功导入公钥,但我的成功到此结束。我知道我需要使用 CAPI 反转字节顺序,所以这可能不是问题。

我已经尝试了一切,包括使用不同CryptVerifyMessageSignatureWithKeyCryptDecodeObject参数加载 blob,但仍然没有运气。

它总是以 结尾GetLastError() == CRYPT_E_ASN1_BADTAG,我认为这意味着 BLOB 不是 ASN1 格式的......谷歌没有告诉任何关于 RSA_private_encrypt 的输出格式......所以我在这里完全迷失了。

这是基于 OpenSSL 的 OS X 代码:

void cr_license_init(const char* lic) {
    __cr_license_ = lic;
    unsigned char lic_encoded[CR_LIC_LEN];

    BIO* b64 = BIO_new(BIO_f_base64());
    BIO* licIn = BIO_new_mem_buf((void*)lic, -1);
    licIn = BIO_push(b64, licIn);

    if(BIO_read(licIn, lic_encoded, CR_LIC_LEN) == CR_LIC_LEN) {

        const unsigned char* key_data = license_pub_der;
        RSA* r = d2i_RSA_PUBKEY(NULL, &key_data, sizeof(license_pub_der));

        if(r != NULL) {
            if(__cr_license_data_ != NULL) {
                free((void*)__cr_license_data_);
            }
            __cr_license_data_ = malloc(CR_LIC_LEN);
            if(RSA_public_decrypt(CR_LIC_LEN, lic_encoded,
    (unsigned char*)__cr_license_data_, r, RSA_PKCS1_PADDING) &lt= 0) {
                free((void*)__cr_license_data_);
                __cr_license_data_ = NULL;
            }
            RSA_free(r);
        }
    }
    BIO_free_all(licIn);
}

这部分代码在 Windows 上运行良好,所以我认为公钥不是问题。

__cr_license_ = lic;
unsigned char lic_encoded[CR_LIC_LEN];

DWORD dwSize;
if(CryptStringToBinaryA(__cr_license_, 0/*autocalculate*/, CRYPT_STRING_BASE64, lic_encoded, &dwSize, NULL, NULL) && dwSize == CR_LIC_LEN) {
HCRYPTPROV hProv;
if(CryptAcquireContext(&hProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
    PCERT_PUBLIC_KEY_INFO pki = NULL;
    DWORD dwKeySize;
    if(CryptDecodeObjectEx(X509_ASN_ENCODING, X509_PUBLIC_KEY_INFO, license_pub_der, sizeof(license_pub_der), CRYPT_ENCODE_ALLOC_FLAG, NULL, &pki, &dwKeySize)) {
        HCRYPTKEY hKey = 0;
        if(CryptImportPublicKeyInfo( hProv, X509_ASN_ENCODING, pki, &hKey)) {

但在那之后,我尝试对消息做的任何事情都会导致CRYPT_E_ASN1_BADTAG. 我尝试CryptMsgOpenToDecode使用CryptMsgUpdate, CryptDecodeObject, CryptVerifyMessageSignatureWithKey- 没有任何效果。

基本上我认为问题在于 owlstead 提到的 pkcs1 和 pkcs7 不兼容。有没有人有使用 MS CAPI 处理 pkcs1 格式导入/转换/等的经验?

非常感谢任何帮助甚至线索!提前致谢!

4

3 回答 3

4

您正在混合更高级别和更低级别的签名格式。OpenSSL 默认采用 PKCS#1 v1.5 签名,其中仅包含签名数据。Windows 似乎采用 PKCS#7 容器。这些可能包含 PKCS#1 v1.5,但这些和其他数据使用 ASN.1 BER 标签/长度格式进行包装。如果 Microsoft API 尝试对此进行解码,它将假定原始签名是容器格式,并且解码将失败。

于 2013-01-25T23:28:58.900 回答
1

除非这很明显以至于您已经尝试过但没有列出它,或者我误解了您的问题,否则我认为您应该使用CryptDecrypt来解密许可证,而不是您在问题中提到的功能。请注意,由于您似乎使用带有 PKCS#1 v1.5 填充的 OpenSSL,而 CryptoAPI 似乎不支持该功能(尚未测试,但规范仅列出 PKCS#1 v2 OAEP),您可能必须使用CRYPT_DECRYPT_RSA_NO_PADDING_CHECK并验证并在解密后手动删除 PKCS#1 v1.5 填充。

于 2013-01-26T14:59:00.427 回答
0

OpenSSL 导出带有 CryptoAPI 不期望的额外标头的密钥。

私钥的标头(采用 ASN.1 表示法):

Offset| Len  |LenByte|
======+======+=======+======================================================================
     0|   630|      3| SEQUENCE : 
     4|     1|      1|    INTEGER : 0
     7|    13|      1|    SEQUENCE : 
     9|     9|      1|       OBJECT IDENTIFIER : rsaEncryption [1.2.840.113549.1.1.1]
    20|     0|      1|       NULL : 
    22|   608|      3|    OCTET STRING : 
                             ... actual key data go here ...

公钥的标头(采用 ASN.1 表示法):

Offset| Len  |LenByte|
======+======+=======+======================================================================
     0|   159|      2| SEQUENCE : 
     3|    13|      1|    SEQUENCE : 
     5|     9|      1|       OBJECT IDENTIFIER : rsaEncryption [1.2.840.113549.1.1.1]
    16|     0|      1|       NULL : 
    18|   141|      2|    BIT STRING UnusedBits:0 : 
                              ... actual key data go here ...

这些标头是导致 CryptDecodeObjectEx 阻塞的原因。它需要 RAW 密钥数据,没有任何标题。

所以,基本上,你需要:

  1. (可选)使用 CryptStringToBinary 将 .PEM 转换为 .DER。
  2. 检查 DER 是否以上述标题开头。为此,您需要阅读 ASN.1 编码的数据。
  3. (可选)跳过上述标题并直接查找密钥的数据(以 SEQUENCE 开头,其中包括 2 INTEGER 用于公钥或 9 INTEGER 用于私钥)。
  4. 将结果提供给 CryptDecodeObjectEx(X509_ASN_ENCODING, RSA_CSP_PUBLICKEYBLOB/PKCS_RSA_PRIVATE_KEY)。
  5. 使用 CryptImportKey 导入密钥。
于 2015-12-04T16:43:53.600 回答