I'm trying to convert the C# code to encrypt text using 3DES ECB (You can copy and paste it on https://dotnetfiddle.net/ to run it)
using System;
using System.Configuration;
using System.Security.Cryptography;
using System.Text;
public class Program
{
public static void Main()
{
string toEncrypt = "testtext";
string key = "testkey";
bool useHashing = true;
byte[] keyArray;
byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);
System.Configuration.AppSettingsReader settingsReader =
new AppSettingsReader();
key = string.IsNullOrEmpty(key) ? (string)settingsReader.GetValue("SecurityKey", typeof(String)) : key;
if (useHashing)
{
MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(key));
hashmd5.Clear();
}
else
{
keyArray = UTF8Encoding.UTF8.GetBytes(key);
}
TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
key = Convert.ToBase64String(keyArray, 0, keyArray.Length);
Console.WriteLine(key);
tdes.Key = keyArray;
tdes.Mode = CipherMode.ECB;
tdes.Padding = PaddingMode.PKCS7;
ICryptoTransform cTransform = tdes.CreateEncryptor();
byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
tdes.Clear();
Console.Write(Convert.ToBase64String(resultArray, 0, resultArray.Length));
}
}
OUTPUT:
Ihs2jX9fWXhn9SWXHyj/dQ== <- md5 secret key
wHL9J7vhm9LZI2W5DQJGKw== <- encrypt result
So I rewrite the above code in NodeJS to use crypto
const crypto = require('crypto');
const md5 = text => {
return crypto
.createHash('md5')
.update(text)
.digest('base64');
}
const encrypt = (text, secretKey) => {
secretKey = md5(secretKey);
console.log(secretKey);
const cipher = crypto.createCipher('des-ede3', secretKey);
const encrypted = cipher.update(text, 'utf8', 'base64');
return encrypted + cipher.final('base64');
};
const encrypted = encrypt('testtext', 'testkey');
console.log(encrypted);
OUTPUT:
Ihs2jX9fWXhn9SWXHyj/dQ== <- md5 secret key
VNa9fDYgPus5IMhUZRI+jQ== <- encrypt result
I think the problem lies in C# and NodeJS Crypto approach in using 3DES ECB. Any idea how to replicate the C# code behaviour in NodeJS?
Triple DES is only defined for 192 bit keys. An MD5 hash only provides 128 bit. There are multiple ways of expanding a potential 128 bit key into a 192 bit key. If we assume that the 128 bit key is made up of two 64 bit sub keys k1 and k2, then C# will create a 192 bit key consisting of k1, k2 and k1 again.
Here is the code that works:
const crypto = require('crypto');
const md5 = text => {
return crypto
.createHash('md5')
.update(text)
.digest();
}
const encrypt = (text, secretKey) => {
secretKey = md5(secretKey);
console.log(secretKey.toString('base64'));
secretKey = Buffer.concat([secretKey, secretKey.slice(0, 8)]); // properly expand 3DES key from 128 bit to 192 bit
const cipher = crypto.createCipheriv('des-ede3', secretKey, '');
const encrypted = cipher.update(text, 'utf8', 'base64');
return encrypted + cipher.final('base64');
};
const encrypted = encrypt('testtext', 'testkey');
console.log(encrypted);
The other issue that you had was using crypto#createCipher
instead of crypto#createCipheriv
. The former has an additional hashing of the "key" which you don't want in this case.
Other potential problems:
Never use ECB mode. It's deterministic and therefore not semantically secure. You should at the very least use a randomized mode like CBC or CTR. It is better to authenticate your ciphertexts so that attacks like a padding oracle attack are not possible. This can be done with authenticated modes like GCM or EAX, or with an encrypt-then-MAC scheme.
Don't use Triple DES nowadays. It only provides at best 112 bit of security even if you use the largest key size of 192 bit. If a shorter key size is used, then it only provides 56 or 57 bits of security. AES would be faster (processors have a special AES-NI instruction set) and even more secure with the lowest key size of 128 bit. There is also a practical limit on the maximum ciphertext size with 3DES. See Security comparison of 3DES and AES.
You should never use a simple hash function to protect your user's passwords. You need to use a strong hashing scheme like PBKDF2, bcrypt, scrypt and Argon2. Be sure to use a high cost factor/iteration count. It is common to choose the cost so that a single iteration takes at least 100ms. See more: How to securely hash passwords?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With