2017-06-18 314 views
0

我在交换“OpenSSL”和“Windows CryptoAPI”之间的公钥问题。公钥以pem格式从OpenSSL导出。我的程序是用C++编写的。我得到公钥并通过“CryptoAPI”加载它。加载公钥后,我加密一些数据并将它们发送给其他应用程序。另一个应用程序不能通过自己的私钥解密接收到的数据。请帮我找到解决方案。在Windows加密和解密在openssl rsa加密

-----BEGIN PUBLIC KEY----- 
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDcJXxao6OzesjaM5VnsYTnHWUN 
z8dosWEETARH6NOqq+hAoMscsv+2MgT0oOYKLf/c8i37YFXnswEan78QnWYO3jtX 
UHfJgXcLcMz7o3lX3OwNqRXgXW6Db95EjPEnLuPCJ2Pafu9E75ZMglkgw9MrIAik 
XKL9u2dc9fkbc7FptQIDAQAB 
-----END PUBLIC KEY----- 

的源代码:

_ServerContextHandle = NULL; 
_EncryptionKeyHandle = NULL; 

void Initialize(char* inPublicKeyByPemFormat) 
{ 
    HCRYPTPROV serverContextHandle; 

    bool result = CryptAcquireContextW(&serverContextHandle, nullptr, nullptr, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) == TRUE; 

    if (result) 
    { 
     _ServerContextHandle = serverContextHandle; 

     byte derPublicKey[2048]; 
     DWORD derPublicKeyLength = 2048; 

     result = CryptStringToBinaryA(inPublicKeyByPemFormat, 0, CRYPT_STRING_BASE64HEADER, derPublicKey, &derPublicKeyLength, nullptr, nullptr) == TRUE; 

     CERT_PUBLIC_KEY_INFO* publicKeyInfo = nullptr; 
     DWORD publicKeyInfoLength; 

     if(result) 
     { 
      result = CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, X509_PUBLIC_KEY_INFO, derPublicKey, derPublicKeyLength, CRYPT_ENCODE_ALLOC_FLAG, nullptr, &publicKeyInfo, &publicKeyInfoLength) == TRUE; 
     } 

     HCRYPTKEY encryptionKeyHandle; 

     if(result) 
     { 
      result = CryptImportPublicKeyInfo(_ServerContextHandle, X509_ASN_ENCODING, publicKeyInfo, &encryptionKeyHandle) == TRUE; 
     } 

     LocalFree(publicKeyInfo); 

     if (result) 
     { 
      _EncryptionKeyHandle = encryptionKeyHandle; 
     } 
    } 
} 


byte* EncryptData(byte* inData, DWORD inDataLength, DWORD* outLength) const 
{ 
    byte* result = nullptr; 

    *outLength = 0; 

    DWORD length = inDataLength; 

    result = CloneByteArray(inData, inDataLength); 

    if (!CryptEncrypt(_EncryptionKeyHandle, NULL, TRUE, 0, result, &length, length)) 
    { 
     delet result; 

     result = new byte[length]; 

     CopyByteArray(inData, result, inDataLength); 

     *outLength = inDataLength; 

     if (!CryptEncrypt(_EncryptionKeyHandle, NULL, TRUE, 0, result, outLength, length)) 
     { 
      delete result; 

      result = nullptr; 

      *outLength = 0; 
     } 
    } 
    else 
    { 
     *outLength = length; 
    } 

    return result; 
} 
+0

如果没有必要的信息,我们无法调试,即使我们想调试您的代码(请调试这不是一个问题,这是一个请求帮助)。 –

+0

在第一个if语句中的第二个函数中,您正在删除结果值,但没有正确拼写。 –

+0

你应该在上面的代码中说明失败的位置。是CryptDecodeObjectEx还是CryptImportPublicKeyInfo还是别的?加载后您应该验证公钥。这可能意味着您需要加载测试密钥对以确保正确性。 OpenSSL是大端,CAPI是小端。你应该从[openssl capi rsa endian site:stackoverflow.com](https://www.google.com/search?q=openssl+capi+rsa+endian+site%3Astackoverflow.com)开始。请参阅[将X509 PEM文件加载到Windows CryptoApi](https://stackoverflow.com/q/1231178/608639)。 – jww

回答

0

CryptEncrypt,对于可能在当时是有道理的,笔者原因,倒着写字节。或者,它将它们写成字节小/小端顺序,而几乎所有其他加密库(包括Windows CNG BCryptEncryptNCryptEncrypt例程)都以字节主/大端顺序写入它们。

因此,您需要反转CryptEncrypt中的数据,并将其转向CryptDecrypt

例如,在.NET Core的RSACryptoServiceProvider.Encrypt中,它调用CapiHelper.EncryptKey,它在返回之前调用CryptEncrypt,然后Array.Reverse

CryptEncrypt documentation具有在备注部分

密文在小尾数格式返回的最后一句话。

+0

感谢您的回复 –