I have an application that encrypts and decrypts a field in C# using Rfc2898DeriveBytes
. I have been trying to work out a cross platform solution using CryptoJS PBKDF2 to write a decrypt method in JavaScript. However, I have not been able to figure out the following 2 issues:
- I can't get the keys to match
- I can't figure out what the IV should be in JavaScript.
Key generation
Generating the key in C# (unfortunately I don't have much control over this as it supports a lot of legacy systems)
private readonly RijndaelManaged _alg = new RijndaelManaged();
public EncryptionManager()
{
var secret = 'D2s1d_5$_t0t3||y_4c3$0m3!1!1!!';
var salt = 'o6805542kcM7c5';
var saltBytes = Encoding.ASCII.GetBytes(salt);
using (var keyDeriver = new Rfc2898DeriveBytes(secret, saltBytes))
{
_alg.Key = keyDeriver.GetBytes(_alg.KeySize / 8); // _alg.KeySize = 256
}
}
The JS code I have for the key generation is:
const secret = CryptoJS.enc.Utf8.parse('D2s1d_5$_t0t3||y_4c3$0m3!1!1!!');
// Encoding the Salt in from UTF8 to byte array
const salt = CryptoJS.enc.Utf8.parse('o6805542kcM7c5');
// Creating the key in PBKDF2 format to be used during the decryption
const key = CryptoJS.PBKDF2(secret.toString(CryptoJS.enc.Utf8), salt, {
keySize: 128 / 32,
iterations: 1000,
});
This should ideally work according to my research but the keys generated in both the codes are never the same. I have burnt a lot of midnight oil scratching my head over what I am doing wrong but I don't see why.
Decryption
The decryption method in C# is as follows:
public string Decrypt(string ciphertext)
{
var cipherTextBytes = Convert.FromBase64String(ciphertext);
var ivSize = BitConverter.ToInt32(cipherTextBytes, 0);
var iv = new byte[ivSize];
var offset = sizeof(int);
Array.Copy(cipherTextBytes, offset, iv, 0, ivSize);
offset += ivSize;
using (var msDecrypt = new MemoryStream(cipherTextBytes, offset, cipherTextBytes.Length - offset))
{
lock (_syncLock)
{
using (var decryptor = _alg.CreateDecryptor(_alg.Key, iv))
using (var decryptStream = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
using (var reader = new StreamReader(decryptStream))
{
return reader.ReadToEnd();
}
}
}
}
My solution for the decryption in JS is:
const decrypt = (encryptedData: string): string => {
// Enclosing the test to be decrypted in a CipherParams object as supported by the CryptoJS libarary
const cipherParams = CryptoJS.lib.CipherParams.create({
ciphertext: CryptoJS.enc.Base64.parse(encryptedData),
});
// What should be the IV be here?
const iv = CryptoJS.enc.Hex.parse(encryptedData);
// Decrypting the string contained in cipherParams using the PBKDF2 key
const decrypted = CryptoJS.AES.decrypt(cipherParams, key, {
mode: CryptoJS.mode.CBC,
// iv,
padding: CryptoJS.pad.Pkcs7,
});
decryptedText = decrypted.toString(CryptoJS.enc.Utf8);
return decryptedText;
}
I am assuming if I could get the correct key and IV, I could solve this. I have looked around a lot for compatible solutions but I'm at a loss as to what I am doing wrong.
Any assistance would be greatly appreciated.