为什么node.js的加密模块给出的结果与用于AES加密的Java的Cipher类不同?

时间:2015-05-29 11:15:59

标签: java node.js encryption aes

我正在尝试理解为什么加密数据在使用Java或Node.js加密时会发生变化,我需要调整node.js代码,使其返回与我在Java上完全相同的加密数据。 (请注意,我无法修改java片段)

Node.js实施:

var crypto = require('crypto');

console.log("\n\n============");
var cKey = new Buffer("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "utf-8");
var cIv = new Buffer("1111111111111111", "utf-8");
var cData = "x";
console.log(cKey);
console.log(cIv);
console.log("UTF-8 Data: " + cData);

var cipher = crypto.createCipheriv("aes-256-cbc", cKey, cIv);
var cipherText = cipher.update(cData, 'utf8', 'hex') + cipher.final('hex');

console.log("Our data: " + cipherText);

上一个代码段将打印以下结果:

<Buffer 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41>
<Buffer 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31>
UTF-8 Data: x
Our data: 0eddfe1857248c7057904455d189cf31

Java实施:

byte[] key = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA".getBytes();
byte[] data = "x".getBytes();
byte[] iv = "1111111111111111".getBytes();
Cipher cipher = Cipher.getInstance("AES");
IvParameterSpec ivspec = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), ivspec);
byte[] result = cipher.doFinal(data);
_print(result);

该片段将打印出来:

17b0ccd594229baa6dabd5e850e07fdf

请注意,我比较了数据,iv和密钥的字节数,这些字节完全相同。

如何修改节点的片段以使其返回相同的java字节?

2 个答案:

答案 0 :(得分:3)

您需要使用相同的操作模式。您的java代码将密码字符串指定为“AES”。这不是完全限定的,因此您的默认JCE提供程序将为“AES”选择其自己的默认值,即“AES / ECB / PKCS5Padding”(在您的情况下),因为它是最基本的,但也是不安全的模式。

您需要在node.js中使用相同的操作模式。您需要更改的唯一两件事是IV大小(ECB不使用IV!)和密码字符串:

var cIv = new Buffer(0);
var cipher = crypto.createCipheriv("aes-256-ecb", cKey, cIv);

请注意,ECB模式本身并不具有语义安全性。此外,密文未经过身份验证,因此您应该使用带有HMAC-SHA256的加密 - 然后 - MAC方案或者像GCM或EAX这样的经过身份验证的模式。

答案 1 :(得分:0)

你的node.js代码看起来正在做它声称要做的事情,因为下面的单元测试成功了:

@Test
public void testAes() throws InvalidKeyException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {
  byte[] key = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA".getBytes();
  byte[] data = "x".getBytes();
  byte[] iv = "1111111111111111".getBytes();
  Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
  IvParameterSpec ivspec = new IvParameterSpec(iv);
  cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), ivspec);
  byte[] result = cipher.doFinal(data);
  assertEquals("0eddfe1857248c7057904455d189cf31", DatatypeConverter.printHexBinary(result).toLowerCase());
}

我怀疑你的Java代码没有做它声称正在做的事情。