2017-02-23 150 views
2

我想转换的C#代码中使用3DES ECB 加密文本(您可以复制并粘贴到https://dotnetfiddle.net/运行它)的NodeJS 3DES ECB加密不等于C#加密

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使用加密

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 

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

回答

1

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

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

} 
+0

因此,你已经能够完成你的*任务*,但是这个职位*回答*你实际提出的问题? – AakashM

+0

@AakashM yep,它的确如此,但我无法在发布日期的2天内接受我自己的回答。我认为这个问题是“如何在NodeJS中复制C#的行为”而不是如何“将C#代码转换为NodeJS”,我将更新问题 –

1

三重DES只为192位密钥的定义。 MD5散列只提供128位。有多种方法将潜在的128位密钥扩展为192位密钥。如果我们假设128位的密钥是由两个64位的子密钥K1 K2 ,然后C#将再次创造由K1一个192位的密钥,K2K1

这里是工作的代码:

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 mode。它是确定性的,因此不具有语义安全性。您至少应该使用像CBCCTR这样的随机模式。最好是验证你的密文,以便像padding oracle attack这样的攻击是不可能的。这可以通过验证模式(如GCM或EAX)或encrypt-then-MAC方案完成。

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

  • 你不应该使用简单的散列函数来保护你的用户密码。你需要使用像PBKDF2,bcrypt,scrypt和Argon2这样强大的散列方案。一定要使用高成本因子/迭代次数。选择成本是很常见的,因此一次迭代至少需要100ms。查看更多:How to securely hash passwords?

+0

嗨,谢谢你的回答,是的,关于ECB模式,它是来自我的雇主业务伙伴的要求。我告诉他们使用AES,但他们更喜欢使用ECB,因为我不能在这里说明。 –