2017-04-21 114 views
3

我需要使用RijndaelManaged在C#中加密數據並在C++代碼中解密。解密C#使用Windows AES加密提供程序在C++中加密的數據

C#代碼加密:

static string Encrypt(string plainText) 
{ 
    byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText); 

    var keyBytes = new byte[] { /* ... 32 bytes of a key */}; 
    byte[] iv = new byte[] { /* ... 16 bytes of IV */ }; 


    var symmetricKey = new RijndaelManaged() 
    { 
     Mode = CipherMode.CBC, 
     Padding = PaddingMode.Zeros, 
     BlockSize = 128, // Must be 128 to be compatible with AES 
     KeySize = 256 
    }; 

    var encryptor = symmetricKey.CreateEncryptor(keyBytes, iv); 

    byte[] cipherTextBytes; 
    using(var memoryStream = new MemoryStream()) 
    { 
     using(var cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write)) 
     { 
      cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length); 
      cryptoStream.FlushFinalBlock(); 
      cipherTextBytes = memoryStream.ToArray(); 
      cryptoStream.Close(); 
     } 
     memoryStream.Close(); 
    } 
    return Convert.ToBase64String(cipherTextBytes); 
} 

但在C解密它,當++代碼,我總是得到NTE_BAD_DATA從CryptDecrypt答覆。這裏是C++代碼(爲清楚起見所有檢查被刪除):

__declspec(dllexport) DWORD Decrypt(char* stringBuffer) 
{ 
string encryptedString(stringBuffer); 

// Decode base64 string to byte array. Works ok, the binary array is the same as the one in C# code. 
vector<BYTE> encryptionBuffer = Base64::decode(encryptedString); 
DWORD bufferSize = encryptionBuffer.size(); 

struct CryptoBlob { 
    BLOBHEADER header; 
    DWORD cbKeySize; 
    BYTE rgbKeyData[32]; 
} keyBlob; 

keyBlob.header.bType = PLAINTEXTKEYBLOB; 
keyBlob.header.bVersion = CUR_BLOB_VERSION; 
keyBlob.header.reserved = 0; 
keyBlob.header.aiKeyAlg = CALG_AES_256; 
keyBlob.cbKeySize = 32; 

BYTE keyData[32] = { /* 32 bytes of a key the same as in C# code */ }; 
BYTE ivData[16] = { /* 16 bytes of IV the same as in C# code */ }; 

memcpy(keyBlob.rgbKeyData, keyData, 32); 

HCRYPTKEY hPubKey; 
HCRYPTPROV hProv; 

CryptAcquireContext(
    &hProv, 
    NULL, 
    NULL, 
    PROV_RSA_AES, 
    CRYPT_VERIFYCONTEXT); 

CryptImportKey(hProv, (const LPBYTE)&keyBlob, sizeof(keyBlob), 0, 0, &hPubKey); 
CryptSetKeyParam(hPubKey, KP_IV, ivData, 0); 

// Here the error happens, the value returned is 0x80090005 (NTE_BAD_DATA) 
DWORD err = CryptDecrypt(hPubKey, 0, TRUE, 0, encryptionBuffer.data(), &bufferSize); 

// overwrite the input buffer with decrypted data 
memset(stringBuffer, 0, encryptedString.length()); 
memcpy(stringBuffer, encryptionBuffer.data(), bufferSize); 

return 0; 
} 

任何想法可能是什麼錯? 謝謝!

+1

我見過與* padding *相同的問題,可能值得研究。 Check here:[CryptoAPI CryptDecrypt function NT_BAD_DATA error](https://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/e2735c15-afe8-4f86-abb8-14e987fb0ccd/cryptoapi-cryptdecrypt-function-ntbaddata-error ?forum = vcgeneral)和這裏:[CryptDecrypt函數](https://msdn.microsoft.com/en-us/library/windows/desktop/aa379913(v = vs.85).aspx)(查看註釋'NTE_BAD_DATA'錯誤代碼)。 –

回答

4

當您將TRUE作爲第三個參數傳遞給CryptDecrypt時,它將嘗試撤銷PKCS#7填充。當它無法撤消該填充時,它會發出NTE_BAD_DATA。

由於您已將加密的填充模式更改爲Pkcs7以外的值,因此您需要通過FALSE並執行手動depadding。

因爲PaddingMode.Zeros不是固有的可撤銷的,所以沒有depadding來執行。

+0

它的工作原理!非常感謝! – ElDog

0

如果上述不是答案,我建議看看它們在C++和C#中都是key/iv,並確保字節數組看起來完全一樣。

最後一個額外的字符可能會導致問題。

如果它們不匹配,請注意在編程語言和跨實現之間,返回的輸出類型(例如signed/unsigned,char/byte array)可能存在差異,這也可能導致問題。

+0

是的,這是非常不清楚我編輯它感謝您的評論。 – didiz