RSA_public_decrypt和MS Crypto API等效

我正在尝试开发许可证validation解决scheme。 许可证使用OpenSSL的RSA_private_encrypt函数在服务器上进行编码。

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

我花了好几天的时间想弄清楚什么是错,但没有运气。 我可以成功导入公钥,但在这里我的成功结束。 我知道,我需要扭转CAPI的字节顺序,所以这可能不是问题。

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

它总是以GetLastError() == CRYPT_E_ASN1_BADTAG结尾,我认为这意味着BLOB不是ASN1格式的… Google不会告诉任何有关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 。 我尝试CryptMsgOpenToDecodeCryptMsgUpdateCryptDecodeObjectCryptVerifyMessageSignatureWithKey – 没有任何工作。

基本上我认为这个问题是在pkcs1和pkcs7不兼容的情况下提到的。 有没有人有与MS CAPI pkcs1格式导入/转换/等工作的经验?

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

Solutions Collecting From Web of "RSA_public_decrypt和MS Crypto API等效"

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

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

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导入密钥。