I have a C# encryption method that uses DES encryption. I need to decrypt that value in a node.js api, I am creating. I have managed to recreate most of the decryption method in the api, but when I pass in the secret and the value to decrypt, I get a different result.
Encryption.cs
public static string Encrypt(string toEncrypt, string key)
{
var des = new DESCryptoServiceProvider();
var ms = new MemoryStream();
des.Key = HashKey(key, des.KeySize / 8);
des.IV = HashKey(key, des.KeySize / 8);
string s = Encoding.UTF8.GetString (des.Key);
des.IV = Encoding.UTF8.GetBytes (key);
byte[] inputBytes = Encoding.UTF8.GetBytes(toEncrypt);
var cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);
cs.Write(inputBytes, 0, inputBytes.Length);
cs.FlushFinalBlock();
return HttpServerUtility.UrlTokenEncode(ms.ToArray());
}
public static string Decrypt(string toDecrypt, string key)
{
var des = new DESCryptoServiceProvider();
var ms = new MemoryStream();
des.Key = HashKey(key, des.KeySize / 8);
des.IV = HashKey(key, des.KeySize / 8);
byte[] inputBytes = HttpServerUtility.UrlTokenDecode(toDecrypt);
var cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write);
cs.Write(inputBytes, 0, inputBytes.Length);
cs.FlushFinalBlock();
var encoding = Encoding.UTF8;
return encoding.GetString(ms.ToArray());
}
public static byte[] HashKey(string key, int length)
{
var sha = new SHA1CryptoServiceProvider();
byte[] keyBytes = Encoding.UTF8.GetBytes(key);
byte[] hash = sha.ComputeHash(keyBytes);
byte[] truncateHash = new byte[length];
Array.Copy(hash, 0, truncateHash, 0, length);
return truncateHash;
}
This is the code I have inherited, and so far I have managed to recreate this:
app.js
var keyHex = 'Secret'
var ciphertext = 'EncryptedValue'
// Decrypt
var keyBytes = CryptoJS.enc.Utf8.parse(keyHex)
var sh1KeyVal = CryptoJS.SHA1(keyBytes)
var trunc = convertWordArrayToUint8Array(sh1KeyVal).slice(0, 8)
var decoded = decodeURI(ciphertext)
var key = trunc.toString(CryptoJS.enc.Utf8)
var bytes = CryptoJS.DES.decrypt(decoded, key, { iv: key });
var originalText = bytes.toString(CryptoJS.enc.Utf8);
console.log('Message: ', originalText);
The hashing process of the secret is something I have been able to recreate and I have confirmed that the value trunc
in the api is the same byte array that the HashKey
method outputs.
However the when I do a simple encryption using var bytes = CryptoJS.DES.decrypt(decoded, key, { iv: key });
it gives a different encrypted value than the C# method, which I think is why the decryption fails.
Something I have found, but am unsure how to address is that when I pass the value of the key and the value to decrypt they need to be strings, however in the C# version the CryptoStream takes a bytearray, so what I am having to do is pass the value to decrypt as a string and I am not sure if this is having an effect.
The same goes for the key, the DESCryptoServiceProvider
accepts the key and iv as byte arrays, however when I convert the crypto-js truncated array it simply converts the literal text of the byte array.
I am currently trying that conversion using the following:
var key = trunc.toString(CryptoJS.enc.Utf8)
Am I missing a step in the process, have I missed something?