I need to encrypt the data in C# using RijndaelManaged and decrypt in C++ code.
C# encryption code:
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);
}
But when decrypting it in C++ code I always get NTE_BAD_DATA reply from CryptDecrypt. Here is C++ code (all checks are removed for clarity):
__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;
}
Any idea what could be wrong? Thanks!
When you pass TRUE
as the 3rd parameter to CryptDecrypt it attempts to undo PKCS#7 padding. When it cannot undo that padding it emits NTE_BAD_DATA.
Since you've changed the padding mode for the encryption to a value other than Pkcs7, you need to pass FALSE
and perform manual depadding.
Since PaddingMode.Zeros is not inherently undoable, there's no depadding to perform.
If the above is not the answer, I'd recommend looking at they key/iv both in C++ and C# and making sure the byte arrays look exactly the same.
An extra char at the end can cause issues.
If they don't match, be aware that between programming languages and across implementations there can be differences in the types of output returned (e.g. signed/unsigned, char/byte array)and that too can cause issues.
User contributions licensed under CC BY-SA 3.0