2017-06-18 188 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

感謝您的回覆 –