NodeJS 3DES ECBencryption不等于C#encryption

我试图转换的C#代码encryption文本使用3DES ECB(您可以复制并粘贴到https://dotnetfiddle.net/运行它)

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 

所以我重写NodeJS上面的代码使用encryption

 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 

我认为问题在于使用3DES ECB的C#和NodeJS Crypto方法。 任何想法如何复制NodeJS中的C#代码行为

好的,只需使用https://www.npmjs.com/package/nod3des即可复制与C#相同的行为&#x3002; 如果你想知道它是如何工作的

https://github.com/4y0/nod3des/blob/master/index.js#L30

 var CryptoJS = require('crypto-js'); var forge = require('node-forge'); var utf8 = require('utf8'); ... _3DES.encrypt = function (key, text){ key = CryptoJS.MD5(utf8.encode(key)).toString(CryptoJS.enc.Latin1); key = key + key.substring(0, 8); var cipher = forge.cipher.createCipher('3DES-ECB', forge.util.createBuffer(key)); cipher.start({iv:''}); cipher.update(forge.util.createBuffer(text, 'utf-8')); cipher.finish(); var encrypted = cipher.output; return ( forge.util.encode64(encrypted.getBytes()) ); } 

三重DES仅为192位密钥定义。 MD5散列只提供128位。 有多种方法将潜在的128位密钥扩展为192位密钥。 如果我们假设128位密钥由两个64位子密钥k1k2组成 ,则C#将再次创build一个由k1k2k1组成的192位密钥。

这里是工作的代码:

 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); 

你遇到的另一个问题是使用crypto#createCipher而不是crypto#createCipheriv 。 前者有一个你不想在这种情况下“钥匙”的哈希值。


其他潜在问题:

  • 切勿使用ECB模式 。 这是确定性的,因此不具有语义上的安全性。 您至less应该使用CBC或CTR等随机模式。 authentication你的密文是更好的,所以像填充甲骨文攻击这样的攻击是不可能的。 这可以通过validation模式,如GCM或EAX,或使用encryption后MACscheme来完成。

  • 现在不要使用三重DES。 即使使用最大的192位密钥,它也只能提供最多112位的安全性。 如果使用较短的密钥大小,则只能提供56或57位的安全性。 AES会更快(处理器有一个特殊的AES-NI指令集),而且最低的128位密钥尺寸更加安全。 3DES的最大密文大小也有一个实际的限制。 请参阅3DES和AES的安全性比较 。

  • 你不应该使用一个简单的散列函数来保护你的用户的密码。 你需要使用像PBKDF2,bcrypt,scrypt和Argon2这样强大的哈希scheme。 一定要使用高成本因子/迭代次数。 select成本是很常见的,因此一次迭代至less需要100ms。 查看更多: 如何安全地哈希密码?