在ColdFusion中encryption,在Node.js中解密

我正在encryptionColdFusion中的string

enc_string = '7001010000006aaaaaabbbbbb'; uid = encrypt(enc_string,'WTq8zYcZfaWVvMncigHqwQ==','AES','Hex'); // secret key for tests only 

结果:

DAEB003D7C9DBDB042C63ED214E85854EAB92A5C1EC555765B565CD8723F9655

后来我想解密Node中的那个string(只是一个例子)

 uid='DAEB003D7C9DBDB042C63ED214E85854EAB92A5C1EC555765B565CD8723F9655' decipher = crypto.createDecipher('aes-192-ecb', 'WTq8zYcZfaWVvMncigHqwQ==') decipher.setAutoPadding(false); dec = decipher.update(uid, 'hex', 'utf8') dec += decipher.final('utf8') 

我尝试了几个密码,但没有运气。 我不想修改ColdFusion代码来使其工作,但如果没有其他机会,我会这样做。 我想用GET从一个站点发送一些encryption的数据到另一个。 有什么build议?

编辑:我尝试所有AES,DES,与IV,没有IV,与&没有填充。 也试过base64。 也没有运气。

使用IV的ColdFusionencryption

 enc_string = '7001010000006aaaaaabbbbbb'; myKey = Tobase64("abcdefghijkl1234"); myIV = charsetDecode("abcdefghijkl9876", "utf-8"); uid=encrypt(enc_string,myKey,'AES/CBC/PKCS5Padding','hex',myIV); 

encryption的uid值是:

614981D0BC6F19A3022FD92CD6EDD3B289214E80D74823C3279E90EBCEF75D90

现在我们把它带到节点:

 var Crypto = require('crypto'); var key = new Buffer('abcdefghijkl1234'); var iv = new Buffer('abcdefghijkl9876'); var encrypted = new Buffer('614981D0BC6F19A3022FD92CD6EDD3B289214E80D74823C3279E90EBCEF75D90', 'hex'); var decipher = Crypto.createDecipheriv('aes-128-cbc', key, iv); var decrypted = decipher.update(encrypted); var clearText = Buffer.concat([decrypted, decipher.final()]).toString(); console.log(clearText); 

结果是:

7001010000006aaaaaabbbbbb

预期的是什么。


问题的根源

最初在Coldfusion中,我使用由以下产生的密钥:

 GenerateSecretKey(algorithm [,keysize]); 

生成了encryption方法所要求的base64密钥。 并没有产生“秘密”。

在Node Crypto方法中,createDecipheriv获取Buffer作为参数。 缓冲区需要秘密,而不是密钥。 我不知道为什么没有IV没有效果。

Coldfusion需要改变什么?

  1. 如果要使用除CF之外的其他语言进行解密,请不要使用GenerateSecretKey
  2. 使用Tobase64(秘密)生成密钥
  3. 使用IV并使用charsetDecode(ivSecret,“utf-8”)生成它
  4. algorithm:AES / CBC / PKCS5Padding
  5. 对于AES / ECB看@Leigh答案

在Node中,每个input都是缓冲区。

我认为这个简短的教程也可以帮助那些在其他语言如cf-> php或cf-> python中有相同问题的人。

对接受的答案作一些澄清和更正

简短的回答:

  • 使用由GenerateSecretKey() “crytographically random”密钥,而不是用Tobase64(secret)创build一个。
  • 尽pipe技术上ECB模式起作用(见下文),但CBC模式是更安全的方法。 对于CBC,请参阅我的完整示例: 在ColdFusion中encryption,在Node.js中解密

更长的答案:

  • 如果您想用其他语言解密,请不要使用GenerateSecretKey

不,使用其他语言的encryption函数生成的值是完全正确的 – 只要符合规范。 这并不意味着这些值可以完全按照“原样”用于任何语言。 它可能需要调整,以符合语言X或Y的实施。 (例如,语言X中的函数可能会希望密钥是hexstring,而不是base64。因此,您可能需要先转换键值)。 原来的代码并没有完全发生,这就是为什么解密不起作用。

GenerateSecretKey()为指定的algorithm生成密码随机密钥 。 (当CF生成base64编码的密钥string时,它可以很容易地被hex编码,密钥的二进制值是重要的。)生成的密钥适用于实现相同encryptionalgorithm和密钥大小的任何语言。 但是,正如我在前面的评论中提到的那样 ,对称encryption只有在一切都匹配的情况下才有效 您必须使用相同的密钥,相同的algorithm,相同的iv等等进行encryption和解密。 在原始代码中,“键”和“algorithm”的值是不同的。 这就是解密失败的原因。

原代码使用crypto.createCipher(algorithm, password) 。 根据API ,“密码”用于派生密码密钥 。 换句话说,Node.js代码使用的是与CF代码完全不同的密钥。 此外,Node.js被configuration为使用192位密钥,而CF代码使用128位密钥。

要回答你原来的问题,是的 – 你可以使用ECB模式(尽pipe强烈build议不要)。 但是,它需要修改CF代码来派生Node.js将使用的相同密码 。 (另一个方向是不可能的,因为它涉及单向哈希。)

为了导出CF中的“密码”,将密钥string解码为二进制,并生成一个md5哈希。 然后将散列解码为二进制,并将其重新编码为base64,以使encrypt()函数开心。

CF:

 plainText = "7001010000006aaaaaabbbbbb"; secretKey = "WTq8zYcZfaWVvMncigHqwQ=="; keyHash = hash(binaryDecode(secretKey, "base64"), "md5"); nodeJSPassword = binaryEncode(binaryDecode(keyHash, "hex"), "base64"); encryptedText = encrypt(plainText, nodeJSPassword, "AES/ECB/PKCS5Padding", "Hex"); writeOutput(encryptedText); 

结果:

 C43E1179C15CD962373A6E28486D6F4ADB12FBB6731EF99C9212474E18D51C70 

在Node.js端,修改代码以使用128位密钥而不是192。此外,密码string首先被解码为二进制。 在创build密码对象时,需要指明inputstring是base64编码的,以确保正确解释。

Node.js的

 var password = 'WTq8zYcZfaWVvMncigHqwQ=='; var passwordBinary = new Buffer(password, "base64"); var encrypted = 'C43E1179C15CD962373A6E28486D6F4ADB12FBB6731EF99C9212474E18D51C70' var crypto = require('crypto'); var decipher = crypto.createDecipher('aes-128-ecb', passwordBinary ); var decrypted = decipher.update(encrypted, 'hex', 'utf8'); decrypted += decipher.final('utf8'); console.log(decrypted); 

结果:

7001010000006aaaaaabbbbbb

话虽如此, build议不要使用ECB模式 。 首选的方法是CBC模式(随机iv ),产生较less的可预测的输出,因此更安全。

  • 比CF使用Tobase64(秘密)生成密钥

沿着同样的路线,虽然你可以在技术上使用任意的string,即“abcdefghijkl1234”,生成一个密钥 – 不。 强encryption的一个非常重要的部分是使用“真正的随机并且包含足够的熵”的秘密密钥。 所以不要自己动手 使用经过validation的函数或库,如专门为该任务devise的GenerateSecretKey()。

您用来encryption和解密的密码不相同。

对于Node将结果解密为期望的string,您应该首先确保对Node中的初始string进行encryption,从而为您提供相同的encryption结果。

考虑以下内容,它运行在Node中的所有已知(对我)AES密码,并尝试获得与Coldfusion相同的encryption结果:

 var crypto = require('crypto'); var key = 'WTq8zYcZfaWVvMncigHqwQ=='; var algorithm; var ciphers = [ 'aes-128-cbc', 'aes-128-cbc-hmac-sha1', 'aes-128-cfb', 'aes-128-cfb1', 'aes-128-cfb8', 'aes-128-ctr', 'aes-128-ecb', 'aes-128-gcm', 'aes-128-ofb', 'aes-128-xts', 'aes-192-cbc', 'aes-192-cfb', 'aes-192-cfb1', 'aes-192-cfb8', 'aes-192-ctr', 'aes-192-ecb', 'aes-192-gcm', 'aes-192-ofb', 'aes-256-cbc', 'aes-256-cbc-hmac-sha1', 'aes-256-cfb', 'aes-256-cfb1', 'aes-256-cfb8', 'aes-256-ctr', 'aes-256-ecb', 'aes-256-gcm', 'aes-256-ofb', 'aes-256-xts', 'aes128', 'aes192', 'aes256' ] function encrypt(text){ var cipher = crypto.createCipher(algorithm, key); var crypted = cipher.update(text,'utf8','hex'); crypted += cipher.final('hex'); return crypted; } for (var i = 0; i < ciphers.length; i++) { algorithm = ciphers[i]; console.log(encrypt("7001010000006aaaaaabbbbbb")); } 

如果你运行这个,你会得到以下输出:

 ab1e8ddd6be53040fcfdf07578704ed9831c4e962eddd36899fc3819b51d6ade ab1e8ddd6be53040fcfdf07578704ed9831c4e962eddd36899fc3819b51d6ade ff19a0b91dad25671632581655f53139ac1f5554383951e255 e4756965c26df5b2e7e2e5291f5a2b1bc835b523ae7e39da0d ff93cfff713798bcf94ff60fb61a6d9d4ae0a7ad6672e77a22 ff19a0b91dad25671632581655f5313940ed1d69d874cf04d7 70ef98bda47bd95e64221c144c4fdec1e5ad1422ca9f4589653214577adf9d9a 918559eaab9a983f91160dbdb2f093f55b0a2bc011fbe1b309 ff19a0b91dad25671632581655f53139cb62004d669030b400 2c4e36eb6b08107bbdf9c79c2f93160211128977181fee45ab 37fed7d50a56f42fa26805a69c38b12b519e59116702a9f0d15a437791600b3a 01f4d909c587684862ea9e27598f5d5c489028a223cc79be1a 0c482981e6aefa068b0c0429ba1e46894c39d7e7f27d114651 01c9d7545c3bfe8594ebf5aef182f5d4930db0555708057785 01f4d909c587684862ea9e27598f5d5c7aa4939a9008ea18c4 6fb304a32b676bc3ec39575e73752ad71255f7615a94ed93f78e6d367281ee41 7494a477258946d781cb53c9b37622248e0ba84a48c577c9df 01f4d909c587684862ea9e27598f5d5c889a935648f5f7061f ea16ecf9ad13756f9bd8ad3fcff2a9e06778647d763f88e679dde519e7155cd6 ea16ecf9ad13756f9bd8ad3fcff2a9e06778647d763f88e679dde519e7155cd6 d0688b6632962acf7905ede7e4f9bd7b2d557e3b828a855208 c0119ab62e5c7a3d932042648291f7cd97c30c9b42c9fa1779 d0f72742cc0415a74e201fcc649f90cf9506eac14e24fd96a9 d0688b6632962acf7905ede7e4f9bd7b5e4921830c30ae8223 d6cd01243405e8741e4010698ab2943526f741cfdb2696b5a6d4e7c14479eccf 2592fb4b19fd100c691598c4bdb82188b6e9d6a6b308d0d627 d0688b6632962acf7905ede7e4f9bd7bf375251be38e1d1e08 d9ae0f940e7c40dcb3a620a5e2a1341819632124af5014bf2f ab1e8ddd6be53040fcfdf07578704ed9831c4e962eddd36899fc3819b51d6ade 37fed7d50a56f42fa26805a69c38b12b519e59116702a9f0d15a437791600b3a ea16ecf9ad13756f9bd8ad3fcff2a9e06778647d763f88e679dde519e7155cd6 

上面输出中包含Coldfusion的encryption结果。

因此,使用Node中可用的AES密码,encryption结果总是与Coldfusion的encryption结果不同。 如果encryption结果始终不同,则不能将其解密为相同的值。

在简单地指定“AES”时, Coldfusion Encryption Docs在描述确切使用哪种algorithm方面并不是很有帮助。 我强烈build议指定一个精确的algorithm来使用,包括使用哪个密钥大小,并select一个在Node中有相应的algorithm。