Java 和 Node 之间的加密不一致
Inconsistencies in encryption between Java and Node
我正在尝试在 Node.js 中复制基于 Java 的加密方案,但不幸的是我得到的结果不一致。
这是 Java 方法:
private Transfer encrypt(byte[] salt, String ticketNumber, String data) throws Exception {
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec spec = new PBEKeySpec(ticketNumber.toCharArray(), salt, 1000, 128);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
String encoded = java.util.Base64.getEncoder().encodeToString(secret.getEncoded());
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] iv ={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
IvParameterSpec ips = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE, secret, ips);
AlgorithmParameters params = cipher.getParameters();
Transfer myRetVal = new Transfer();
byte[] ivBytes = params.getParameterSpec(IvParameterSpec.class).getIV();
//Set some decrypt information
myRetVal.setIv(Base64.encodeBase64String(ivBytes));
//Set the attendee data
myRetVal.setData(Base64.encodeBase64String(cipher.doFinal(data.getBytes())));
//Set the hashed Ticket number
myRetVal.setTicketNumberHashed(Base64.encodeBase64String(getHash(hashIterations, ticketNumber, salt)));
return myRetVal;
}
我的节点版本:
exports.getEncryptedString = function(salt, password, data) {
var iv = new Buffer('0000000000000000');
var key = crypto.pbkdf2Sync(password, salt, 1000, 16, 'sha1');
var cipher = crypto.createCipheriv('aes-128-cbc', key, iv);
return cipher.update(data, 'utf8', 'base64') + cipher.final('base64');
};
当我向两个函数传递字符串 "SomeJSON" 和相同的密钥时,我得到不同的加密结果。
来自 Java:ENnQzWowzrl7LQchRmL7sA==
来自节点:TGreJNmQH92gHb1bSy4xAA==
我无法弄清楚我的 Node 实现有什么不同。
new Buffer('0000000000000000')
默认使用 utf8 编码,但 UTF-8 中的 "0"
是字节 0x30
而在 Java 中你使用 0x00 字节作为 IV .你想要的是
var iv = new Buffer('00000000000000000000000000000000', 'hex');
或
var iv = new Buffer(16);
iv.fill(0);
完成测试后,您应该更改程序,为每次加密生成一个新的 IV。 IV 不必是秘密的,因此您可以简单地将其添加到密文中。当你想稍后解密它时,你可以将 IV 切掉(AES 为 16 字节)并在解密期间使用它。
我正在尝试在 Node.js 中复制基于 Java 的加密方案,但不幸的是我得到的结果不一致。
这是 Java 方法:
private Transfer encrypt(byte[] salt, String ticketNumber, String data) throws Exception {
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec spec = new PBEKeySpec(ticketNumber.toCharArray(), salt, 1000, 128);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
String encoded = java.util.Base64.getEncoder().encodeToString(secret.getEncoded());
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] iv ={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
IvParameterSpec ips = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE, secret, ips);
AlgorithmParameters params = cipher.getParameters();
Transfer myRetVal = new Transfer();
byte[] ivBytes = params.getParameterSpec(IvParameterSpec.class).getIV();
//Set some decrypt information
myRetVal.setIv(Base64.encodeBase64String(ivBytes));
//Set the attendee data
myRetVal.setData(Base64.encodeBase64String(cipher.doFinal(data.getBytes())));
//Set the hashed Ticket number
myRetVal.setTicketNumberHashed(Base64.encodeBase64String(getHash(hashIterations, ticketNumber, salt)));
return myRetVal;
}
我的节点版本:
exports.getEncryptedString = function(salt, password, data) {
var iv = new Buffer('0000000000000000');
var key = crypto.pbkdf2Sync(password, salt, 1000, 16, 'sha1');
var cipher = crypto.createCipheriv('aes-128-cbc', key, iv);
return cipher.update(data, 'utf8', 'base64') + cipher.final('base64');
};
当我向两个函数传递字符串 "SomeJSON" 和相同的密钥时,我得到不同的加密结果。
来自 Java:ENnQzWowzrl7LQchRmL7sA==
来自节点:TGreJNmQH92gHb1bSy4xAA==
我无法弄清楚我的 Node 实现有什么不同。
new Buffer('0000000000000000')
默认使用 utf8 编码,但 UTF-8 中的 "0"
是字节 0x30
而在 Java 中你使用 0x00 字节作为 IV .你想要的是
var iv = new Buffer('00000000000000000000000000000000', 'hex');
或
var iv = new Buffer(16);
iv.fill(0);
完成测试后,您应该更改程序,为每次加密生成一个新的 IV。 IV 不必是秘密的,因此您可以简单地将其添加到密文中。当你想稍后解密它时,你可以将 IV 切掉(AES 为 16 字节)并在解密期间使用它。