我正在尝试开发许可证验证解决方案。许可证使用OpenSSL的RSA_private_encrypt
函数在服务器上进行编码。
对于Mac OX X,我使用RSA_public_decrypt
,它就像一个魅力。在Windows上我必须使用非常小的代码,因此我无法与OpenSSL或其他lib链接,我必须使用MS Crypto API。
我花了几天时间试图找出问题所在,但没有运气。我可以成功导入公钥,但在这里我的成功结束了。 我知道我需要用CAPI来反转字节顺序,所以这可能不是问题。
我已经尝试了所有内容,包括CryptVerifyMessageSignatureWithKey
和CryptDecodeObject
来加载不同参数的blob,但仍然没有运气。
它始终以GetLastError() == CRYPT_E_ASN1_BADTAG
结束,我认为这意味着BLOB不是ASN1格式化的... Google没有告诉RSA_private_encrypt的输出格式...所以我完全迷失了。< / p>
以下是基于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) <= 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
- 无效。
基本上我认为问题在于pkcs1和pkcs7不兼容,因为owlstead提到过。有没有人有使用MS CAPI的pkcs1格式导入/转换/等的经验?
任何帮助甚至线索都非常受欢迎!提前谢谢!
答案 0 :(得分:4)
您正在混合使用更高级别和更低级别的签名格式。 OpenSSL默认使用PKCS#1 v1.5签名,其中仅包含签名数据。 Windows似乎认为PKCS#7容器。这些可能包含PKCS#1 v1.5,但这些和其他数据使用ASN.1 BER标记/长度格式包装。如果Microsoft API尝试对此进行解码,则会假定原始签名是容器格式,并且解码将失败。
答案 1 :(得分:1)
除非这是显而易见的,你已经尝试但忽略了列出它,否则我误解了你的问题,我认为你应该使用CryptDecrypt来解密许可证,而不是你在问题中提到的功能。请注意,由于您似乎使用OpenSSL和PKCS#1 v1.5填充而CryptoAPI似乎不支持(未测试,但规格仅列出PKCS#1 v2 OAEP),您可能必须使用{{ 1}}并在解密后手动验证并删除PKCS#1 v1.5填充。
答案 2 :(得分: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密钥数据,没有任何标题。
所以,基本上,你需要: