为什么 node.js 的加密模块给出的结果与 Java 的 AES 加密的密码 class 不同?
Why does node.js's crypto module give a different result than Java's Cipher class for AES encryption?
我试图理解为什么在使用 Java 或 Node.js 加密时加密数据会发生变化,我需要调整 node.js 代码以使其成为 return与我在 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 和密钥的字节,它们完全相同。
我如何修改节点的代码片段以使其 return 与 java 的字节相同?
您需要使用相同的操作方式。您的 java 代码将密码字符串指定为 "AES"。这不是完全合格的,因此您的默认 JCE 提供程序将 select 它自己的 "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 等经过身份验证的模式。
您的 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 代码没有按照它声称的那样去做。
我试图理解为什么在使用 Java 或 Node.js 加密时加密数据会发生变化,我需要调整 node.js 代码以使其成为 return与我在 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 和密钥的字节,它们完全相同。
我如何修改节点的代码片段以使其 return 与 java 的字节相同?
您需要使用相同的操作方式。您的 java 代码将密码字符串指定为 "AES"。这不是完全合格的,因此您的默认 JCE 提供程序将 select 它自己的 "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 等经过身份验证的模式。
您的 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 代码没有按照它声称的那样去做。