javascript - 与 java 相比,节点中的 AES 加密是不同的输出
问题描述
我正在尝试将用于 AES ECB 加密的 Java 代码移植到 node.js
问题是java和node的输出不一样。
这是java代码
public static final String DEFAULT_ENCODING = "UTF-8";
public static final String SEC_PROVIDER = "SunJCE";
public static final String AES_ALGORITHM = "AES";
public static final String RIJNDAEL_CIPHER = **"Rijndael/ECB/NoPadding"**;
public static final int **CIPHER_PAD_SIZE = 32**;
public static final String HEX_KEY = "3b6ce332ca3b6519eac769710f41ca5c";
public static String encryptData(String text, String hexKey) throws
Exception {
byte[] b1 = Hex.decodeHex(HEX_KEY.toCharArray());
SecretKey key = new SecretKeySpec(b1, AES_ALGORITHM);
Cipher cipher = Cipher.getInstance(RIJNDAEL_CIPHER, SEC_PROVIDER);
text = padRightToMod(text, CIPHER_PAD_SIZE);
byte[] buf = text.getBytes(DEFAULT_ENCODING);
cipher.init(Cipher.ENCRYPT_MODE, key);
buf = cipher.doFinal(buf);
String result = new String(Hex.encodeHex(buf));
result = result.toUpperCase();
return result;
}
// ensure block size of 32
public static String padRightToMod(String text, int mod) {
if (text == null || mod <= 0) {
return text;
}
final int len = text.length();
StringBuilder buf = new StringBuilder(512);
buf.append(text);
for (int i = len; i % mod > 0; i++) {
buf.append(" ");
}
String rs = buf.toString();
System.out.println(rs.length());
return rs;
}
// Call to the encrypt function
String encText = encryptData("Hello", HEX_KEY);
结果是 CC0AC95B5FFD4758DBFA40F909C285F0F86A8F19ED1A12C1BFC098348A2AC683
并使用此 javascript 代码
crypto = require('crypto');
function encrypt(data,key) {
var cipher = crypto.createCipher('**aes-128-ecb**', key); //create aes cipher
var encrypted = cipher.update(data,'utf8', 'hex'); //output as hex
return encrypted;
}
function padRightTo32(str) // ensure block size of 32
{
len=str.length;
for(i=len; i%32>0; i++){
str=str +" ";
}
return str;
}
// call to encryption function
hexkey="3b6ce332ca3b6519eac769710f41ca5c"
encStr=encrypt(padRightTo32("Hello"),hexKey);
console.log(encStr);
结果是 1B928CF3C18D53BA5138DD1484D181939FD2B7BB2A17AE6A79664488B5C12652
==== 更新 ======
我用这个代码尝试了https://github.com/Snack-X/rijndael-js实现形式 github
const Rijndael = require("./node_modules/node-rijndael-master");
function padRightTo32(str)
{
len=str.length;
for(i=len; i%32>0; i++){
str=str +" ";
}
console.log(str);
console.log(str.length);
return str;
}
let key = "3b6ce332ca3b6519eac769710f41ca5c";
let original = padRightTo32("Hello");
let cipher = new Rijndael(key, "ecb");
let ciphertext = cipher.encrypt(original, 128);
console.log(ciphertext.toString("hex"));
我得到这个结果 e97282fb5838a9c78e6df1f1b4aad108aa010418ec573d74b9c991f4e897e752 但不是我在 java 中得到的加密文本。尝试 256 块大小也无济于事。
我缺少什么导致不同的输出?
解决方案
关于您的密钥,您必须使用缓冲区将您的十六进制字符串转换为二进制数据(参见例如在 node.js 上使用 aes-ecb 加密二进制数据)。
此外,您必须使用该方法crypto.createCipheriv
来实例化密码(参见例如https://nodejs.org/api/crypto.html#crypto_crypto_createcipheriv_algorithm_key_iv_options)。当前使用的(已弃用)方法crypto.creataCipher
需要密码并从密码生成密钥(参见例如https://nodejs.org/api/crypto.html#crypto_crypto_createcipher_algorithm_password_options)。
以下代码
crypto = require('crypto');
function encrypt(data,key) {
var cipher = crypto.createCipheriv('aes-128-ecb', key,''); //create aes-128 cipher
var encrypted = cipher.update(data,'utf8', 'hex'); //output as hex
return encrypted;
}
function padRightTo32(str) { // ensure block size of 32
len=str.length;
for(i=len; i%32>0; i++) {
str=str +" ";
}
return str;
}
// call to encryption function
var hexKey = new Buffer('3b6ce332ca3b6519eac769710f41ca5c', 'hex'); // 16 Byte-key
encStr=encrypt(padRightTo32("Hello"),hexKey);
console.log(encStr);
有输出
cc0ac95b5ffd4758dbfa40f909c285f0f86a8f19ed1a12c1bfc098348a2ac683
这等于 Java 代码的输出。
在 Java 中,密钥的长度定义了使用的 AES 变体,例如,如果您选择 16 字节密钥,则使用 AES-128,如果选择 32 字节密钥,则使用 AES-256。在 nodejs 代码中,您必须明确指定 AES 变体,即aes-128-ecb
16 字节密钥和aes-256-ecb
32 字节密钥等。
正如评论中已经提到的,ECB
不是安全模式(参见例如https://crypto.stackexchange.com/questions/20941/why-shouldnt-i-use-ecb-encryption)。
我不知道Java 中的密码实例化Rijndael/ECB/NoPadding
之间是否真的存在差异。AES/ECB/NoPadding
在我的测试用例中,至少结果是相同的。因此,对于 nodejs 代码,选择aes-128-ecb
(对于 16 字节密钥)或aes-256-ecb
(对于 32 字节密钥)应该有效。
推荐阅读
- r - 对多个绘图使用多个选项
- android - 无法解决:com.airbnb.android:lottie:2.5.1
- c# - Azure 离线 SQL Lite DB 存储非常慢
- python - '020-06-08 17:11:02+00:00' 我想使用 datetime 从 Python 中的这种时间格式中提取日期
- objective-c - 如何检查 OC 或 Swift 中未使用的变量
- xampp - #2002 - 连接被拒绝 - 服务器没有响应(或本地服务器的套接字配置不正确)
- angular - 如何在谷歌云功能中设置自定义声明?
- java - 如何开发一个可以使用 java 回答问题的消息机器人
- angular - 更改角度组件中的通知图标
- php - oci8、php7 和 Oracle 10.1 兼容性