Nodejs和java的aes-128-ecb加密结果不一样
Nodejs和java的aes-128-ecb加密结果不一样
nodejs代码如下:
encryptUtils.aesEncrypt = function(data, secretKey) { var cipher = crypto.createCipher(‘aes-128-ecb’,secretKey); return cipher.update(data,‘utf8’,‘hex’) + cipher.final(‘hex’); }
java代码:
public static String encryptAESBy128ECB(String content, String password) throws Exception { Cipher cipher = Cipher.getInstance(“AES/ECB/PKCS5Padding”); byte[] raw = password.getBytes(“utf-8”); SecretKeySpec skeySpec = new SecretKeySpec(raw, “AES”); cipher.init(Cipher.ENCRYPT_MODE, skeySpec); byte[] encrypted = cipher.doFinal(content.getBytes(“utf-8”)); return bytesToHexString(encrypted); } 经测试两个结果不一样,有谁遇到过吗,目前的业务需求是nodejs和android之间的加解密通讯,然后遇到了这个问题
标题:Node.js 和 Java 的 AES-128-ECB 加密结果不一样
内容:
在实现 Node.js 和 Java 之间的 AES-128-ECB 加密时,经常会遇到加密结果不一致的问题。这是因为两者在处理加密过程中的某些细节有所不同。下面我们将通过具体的代码示例来解释这一现象,并提供解决方案。
Node.js 代码示例
const crypto = require('crypto');
function aesEncrypt(data, secretKey) {
const cipher = crypto.createCipher('aes-128-ecb', secretKey);
return cipher.update(data, 'utf8', 'hex') + cipher.final('hex');
}
// 示例调用
const data = "HelloWorld";
const secretKey = "0123456789abcdef"; // 16字节密钥
console.log(aesEncrypt(data, secretKey));
Java 代码示例
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
public class AesUtil {
public static String encryptAESBy128ECB(String content, String password) throws Exception {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
byte[] raw = password.getBytes("utf-8");
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(content.getBytes("utf-8"));
return bytesToHexString(encrypted);
}
private static String bytesToHexString(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}
// 示例调用
public static void main(String[] args) throws Exception {
String data = "HelloWorld";
String secretKey = "0123456789abcdef"; // 16字节密钥
System.out.println(encryptAESBy128ECB(data, secretKey));
}
}
解释
-
填充模式不同:
- Node.js 默认使用
aes-128-ecb
,这通常意味着没有填充(即 ECB 模式下的原始数据长度必须是块大小的倍数)。 - Java 使用的是
AES/ECB/PKCS5Padding
,这意味着数据会自动进行 PKCS5 填充以确保其长度为块大小的倍数。
- Node.js 默认使用
-
密钥长度:
- 在 Node.js 中,密钥长度必须恰好为 16 字节(128 位)。
- 在 Java 中,密钥长度同样需要为 16 字节(128 位),但 Java 会自动将字符串转换为字节数组。
解决方案
为了使 Node.js 和 Java 的加密结果一致,可以在 Node.js 中显式地添加 PKCS5 填充:
function aesEncryptWithPadding(data, secretKey) {
const blockSize = 16;
const paddingLength = blockSize - (data.length % blockSize);
const paddedData = data + String.fromCharCode(paddingLength).repeat(paddingLength);
const cipher = crypto.createCipheriv('aes-128-ecb', secretKey, null);
return cipher.update(paddedData, 'utf8', 'hex') + cipher.final('hex');
}
这样可以确保 Node.js 和 Java 的加密结果一致。
在 Node.js 和 Java 中使用 AES-128-ECB 加密时,可能会因为不同的默认设置导致加密结果不同。具体来说,Node.js 默认可能没有填充数据,而 Java 使用了 PKCS5Padding。
以下是调整后的 Node.js 和 Java 示例代码:
Node.js 示例代码
const crypto = require('crypto');
function aesEncrypt(data, secretKey) {
const cipher = crypto.createCipheriv('aes-128-ecb', secretKey, null);
cipher.setAutoPadding(true); // 确保处理填充
return cipher.update(data, 'utf8', 'hex') + cipher.final('hex');
}
console.log(aesEncrypt('Hello World!', 'your_secret_key'));
Java 示例代码
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
public class AesEncryption {
public static String encryptAESBy128ECB(String content, String password) throws Exception {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
byte[] raw = password.getBytes("utf-8");
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(content.getBytes("utf-8"));
return bytesToHexString(encrypted);
}
private static String bytesToHexString(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}
public static void main(String[] args) throws Exception {
System.out.println(encryptAESBy128ECB("Hello World!", "your_secret_key"));
}
}
解释
- Node.js: 使用
createCipheriv
创建Cipher
对象,并显式指定setAutoPadding(true)
来确保填充。 - Java: 使用
"AES/ECB/PKCS5Padding"
来确保使用相同的填充方式。
通过上述修改,你应该能够获得一致的加密结果。