Encrypt in Coldfusion, Decrypt in Node.js

时间:2016-04-07 10:38:30

标签: node.js encryption coldfusion aes

I'm encrypting a string in ColdFusion

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

Result:

DAEB003D7C9DBDB042C63ED214E85854EAB92A5C1EC555765B565CD8723F9655

Later I want to decrypt that string in Node (just an example)

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

I have tried few ciphers but with no luck. I would like not to modify the ColdFusion code to make it work, but if there is no other chance I will do that. I want to send some ciphered data with GET from one site to another. Any advice?

EDIT: I tried all AES, DES, with IV, without IV, with & without padding. Tried also base64. Also with no luck.

2 个答案:

答案 0 :(得分:3)

accepted answer

的一些澄清和更正

简答:

  • 使用GenerateSecretKey()生成的“加密随机”密钥,而不是使用Tobase64(secret)创建密钥。
  • 虽然从技术上讲ECB模式有效(见下文),但CBC模式更适合作为更安全的方法。对于CBC,请参阅我的完整示例:Encrypt in ColdFusion, Decrypt in Node.js

更长的答案:

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

不,将生成的值与其他语言的加密函数一起使用是完全可以的 - 只要它们符合规范即可。这并不意味着这些值可以完全“按原样”用于任何语言。可能需要调整以符合语言X或Y的实现。 (例如,语言X中的函数可能希望键是十六进制字符串,而不是base64。因此您可能需要首先转换键值)。这在原始代码中并没有发生,这就是为什么解密不起作用的原因。

GenerateSecretKey()为指定的算法生成cryptographically random key。 (虽然CF生成base64编码的密钥字符串,但它可以很容易地进行十六进制编码。密钥的二进制值是重要的。)生成的密钥适用于任何实现该密钥的语言。加密算法和密钥大小。但是,正如我在earlier comments中提到的,对称加密仅在所有内容匹配时有效。您必须使用相同的密钥,相同的算法,相同的iv,等等来进行加密和解密。在原始代码中,“密钥”和“算法”值都不同。这就是解密失败的原因。

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

要回答您的原始问题,是的 - 您可以使用ECB模式(尽管强烈建议不要这样做)。但是,它需要修改CF代码以导出相同的密码 Node.js将使用。 (另一个方向是不可能的,因为它涉及单向散列。)

要在CF中派生“密码”,请将密钥字符串解码为二进制并生成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.此外,密码字符串首先被解码为二进制。创建密码对象时,需要指示输入字符串是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

话虽如此,Using ECB mode is NOT recommended。首选方法是CBC模式(带有随机iv),它产生的可预测输出较少,因此更安全。

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

沿着同样的路线,虽然你可以在技术上使用任意字符串,即“abcdefghijkl1234”,来生成一个键 - 不要。强加密的一个非常重要的部分是使用"truly random and contain sufficient entropy"的密钥。所以不要自己动手。使用经过验证的函数或库,例如GenerateSecretKey(),它是专门为该任务设计的。

答案 1 :(得分:1)

您用于加密和解密的密码不相等。

要让Node将您的结果解密为预期的字符串,您应该首先确保加密Node中的初始字符串会为您提供相同的加密结果。

考虑以下内容,它贯穿Node中所有已知的(对我而来的)AES密码,并尝试获得与Coldfusion相同的加密结果:

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获得的加密结果在上面的输出中

因此,使用Node中提供的AES密码,加密结果始终与Coldfusion的加密结果不同。如果加密结果总是不同,则无法将其解密为相同的值。

在简单指定&#34; AES&#34; 时,Coldfusion Encryption Docs对于准确描述使用哪种算法并不是很有帮助。我强烈建议指定要使用的精确算法,包括使用哪个密钥大小,并选择在Node中具有相应算法的算法。