I am attempting to replicate some JS code in my C#. I found a decent amount of information online but can't seem to get my scenario to work. I don't have the ability to change how it's encrypted, so I can only adjust how I decrypt it.
Here's the JS code I'm trying to replicate: *note that password is a string and data is a TypedArray We can see it uses AES 128 CBC. It derives a key using pbkdf2. The IV is the first 16 bytes of the original data. It's using the node.js crypto library.
function Decrypt(password, data) {
let decryptedData;
try {
const iv = data.subarray(0, 16);
const decipher = crypto.createDecipheriv('aes-128-cbc', crypto.pbkdf2Sync(password, iv, 100, 16, 'sha1'), iv);
decryptedData = Buffer.concat([decipher.update(data.subarray(16)), decipher.final()]);
return decryptedData;
} catch (e) {
return e.stack;
}
}
Here's my current C# Method: IV is declared at the class level as an empty 16 byte array I used some print statements to confirm that the information passed into the decryptor is identical to what the JS function sees. Meaning the IV is pulled out correctly, and the key that I derive is the same as the JS, as well as the data that I actually pass in.
private string Decrypt(string password, byte[] data)
{
// pull the first 16 bytes of data and copy to the IV
Array.Copy(data, IV, 16);
// create a new array to copy the data without the IV
byte[] dataToDecrypt = new byte[data.Length - 16];
// copy the data to the new array
Array.Copy(data, 16, dataToDecrypt, 0, dataToDecrypt.Length);
// generate key from password and IV
Rfc2898DeriveBytes k2 = new Rfc2898DeriveBytes(password, IV, 100, HashAlgorithmName.SHA1);
Aes decAlg = Aes.Create();
decAlg.Mode = CipherMode.CBC;
decAlg.Padding = PaddingMode.PKCS7;
//decAlg.Padding = PaddingMode.Zeros;
decAlg.BlockSize = 128;
decAlg.Key = k2.GetBytes(16);
decAlg.IV = IV;
MemoryStream decryptionStreamBacking = new MemoryStream();
CryptoStream decrypt = new CryptoStream(decryptionStreamBacking, decAlg.CreateDecryptor(), CryptoStreamMode.Write);
decrypt.Write(dataToDecrypt, 0, dataToDecrypt.Length);
decrypt.Flush();
decrypt.Close();
k2.Reset();
string data2 = new UTF8Encoding(false).GetString(decryptionStreamBacking.ToArray());
return data2;
}
If I use any padding mode other than zeros, then the decryption will toss the error listed in the title, if I use zeros, then I get gibberish.
As far as I can tell, I'm doing everything that the JS is doing so I am not sure what I'm missing.
Here's the original encryption method used, also in JS:
function Encrypt(password, data) {
let encryptedData;
try {
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv('aes-128-cbc', crypto.pbkdf2Sync(password, iv, 100, 16, 'sha1'), iv);
encryptedData = Buffer.concat([iv, cipher.update(data), cipher.final()]);
return encryptedData;
} catch (e) {
return e.stack;
}
}
Based on my research it may have something to do with the data that's being inputted, but it's same for both of them, and I don't read it as a string or convert it to that in C# before trying to decrypt it. I'm thinking I'm missing something about how node-crypto interacts with the data that isn't happening in C#.
I've also tried:
- trying to use clearscript to run the JS directly in C# so I didn't need to fuss with all of this, I can't get it to use the crypto module, and the idea was kind of dumb in the first place so I jumped ship.
- I've tried the Rijndael out of naivity, didn't work
- I tried some different settings, including all of the different padding modes, got nothing
- I tried encrypting new data and seeing if the issue was me messing with the original data, issue persisted
- I tried different ways of writing the decrypt alg function, I heard about some quirks .net used to have and figured that could be it, but all methods of writing it have the same outcome. This includes using AesCryptoServiceProvider and AesManaged
I ended up asking chat GPT and there were some adjustments that needed to be made, I'm not sure what in particular fixed it, but the big changes are that I defined my IV within the function, and I changed to UTF-8.