Java 和 Java 脚本中的加密和解密 (Nodejs)
Encryption and Decryption in Java and Javascript (Nodejs)
我在 Java 中加密文本并想在 Java 脚本中解密,反之亦然,我的 Java 代码如下所示
Cipher c = Cipher.getInstance("AES/GCM/NoPadding");
SecretKeySpec k = new SecretKeySpec(this.key.getBytes(), "AES");
c.init(Cipher.ENCRYPT_MODE, k);
byte[] encryptedData = c.doFinal(this.value.getBytes());
byte[] iv = c.getIV();
sb.append(new String(Base64.getEncoder().encode(iv)));
sb.append(';');
sb.append(new String(Base64.getEncoder().encode(encryptedData)));
// send sb.toString() to the other end
我在 Nodejs 中尝试了 node-forge 和 elliptic 解密,在 node-forge 中我有一个错误抱怨我没有标签,有人可以在 Nodejs 中提供解决方案吗?
Java脚本代码
function convertFromMxBase64(FormatEncryptedString) {
const speratorIndex = FormatEncryptedString.indexOf(';');
const encryptedBase64 = mxFormatEncryptedString.substr(speratorIndex + 1);
const ivBase64 = mxFormatEncryptedString.substr(0, speratorIndex);
return {
iv: forge.util.createBuffer(forge.util.decode64(ivBase64), 'utf8'),
payload: forge.util.createBuffer(forge.util.decode64(encryptedBase64), 'utf8')
};
}
function decrypt() {
let { iv, payload } = convertFromMxBase64(mxCombi);
const key = forge.util.createBuffer(theKey, 'utf8');
var cipher = forge.cipher.createDecipher("AES-GCM", key); // forge.rc2.createDecryptionCipher(key);
cipher.start({ iv });
cipher.update(payload);
cipher.finish();
var encrypted = cipher.output;
// outputs encrypted hex
console.log(encrypted.toHex());
}
GCM 模式根据定义使用 authenticity/integrity 检查所需的标签。
NodeJS 端的标签问题是由于没有考虑身份验证标签引起的。在 Java 方面,这不是必需的,因为 SunJCE 提供者通过将标记附加到密文来自动执行此操作:因此,结果的最后 16 个字节是标记。相比之下,在 NodeJS 端,密文和标签是分离处理的,因此这两部分必须 显式 分开,例如:
var ciphertext = forge.util.createBuffer(payload.data.substring(0, payload.length() - 16));
var tag = forge.util.createBuffer(payload.data.substring(payload.length() - 16));
标签和密文必须按如下方式传递给 cipher
实例:
cipher.start({ iv:iv, tag:tag }); // apply tag
cipher.update(ciphertext); // apply ciphertext
另一个错误是在创建iv
和payload
时使用了UTF-8编码。这是错误的,数据必须作为二进制字符串传递,即 'utf8'
必须替换为 'binary'
或完全删除。
iv: forge.util.createBuffer(forge.util.decode64(ivBase64)),
payload: forge.util.createBuffer(forge.util.decode64(encryptedBase64))
此外,在 Java 代码的 getBytes()
中应指定编码,例如getBytes(StandardCharsets.UTF_8)
。如果不这样做,将使用 platform-dependent 默认编码,这意味着可以根据环境应用不同的编码。
通过这些更改,解密在 NodeJS 端进行。
我在 Java 中加密文本并想在 Java 脚本中解密,反之亦然,我的 Java 代码如下所示
Cipher c = Cipher.getInstance("AES/GCM/NoPadding");
SecretKeySpec k = new SecretKeySpec(this.key.getBytes(), "AES");
c.init(Cipher.ENCRYPT_MODE, k);
byte[] encryptedData = c.doFinal(this.value.getBytes());
byte[] iv = c.getIV();
sb.append(new String(Base64.getEncoder().encode(iv)));
sb.append(';');
sb.append(new String(Base64.getEncoder().encode(encryptedData)));
// send sb.toString() to the other end
我在 Nodejs 中尝试了 node-forge 和 elliptic 解密,在 node-forge 中我有一个错误抱怨我没有标签,有人可以在 Nodejs 中提供解决方案吗?
Java脚本代码
function convertFromMxBase64(FormatEncryptedString) {
const speratorIndex = FormatEncryptedString.indexOf(';');
const encryptedBase64 = mxFormatEncryptedString.substr(speratorIndex + 1);
const ivBase64 = mxFormatEncryptedString.substr(0, speratorIndex);
return {
iv: forge.util.createBuffer(forge.util.decode64(ivBase64), 'utf8'),
payload: forge.util.createBuffer(forge.util.decode64(encryptedBase64), 'utf8')
};
}
function decrypt() {
let { iv, payload } = convertFromMxBase64(mxCombi);
const key = forge.util.createBuffer(theKey, 'utf8');
var cipher = forge.cipher.createDecipher("AES-GCM", key); // forge.rc2.createDecryptionCipher(key);
cipher.start({ iv });
cipher.update(payload);
cipher.finish();
var encrypted = cipher.output;
// outputs encrypted hex
console.log(encrypted.toHex());
}
GCM 模式根据定义使用 authenticity/integrity 检查所需的标签。
NodeJS 端的标签问题是由于没有考虑身份验证标签引起的。在 Java 方面,这不是必需的,因为 SunJCE 提供者通过将标记附加到密文来自动执行此操作:因此,结果的最后 16 个字节是标记。相比之下,在 NodeJS 端,密文和标签是分离处理的,因此这两部分必须 显式 分开,例如:
var ciphertext = forge.util.createBuffer(payload.data.substring(0, payload.length() - 16));
var tag = forge.util.createBuffer(payload.data.substring(payload.length() - 16));
标签和密文必须按如下方式传递给 cipher
实例:
cipher.start({ iv:iv, tag:tag }); // apply tag
cipher.update(ciphertext); // apply ciphertext
另一个错误是在创建iv
和payload
时使用了UTF-8编码。这是错误的,数据必须作为二进制字符串传递,即 'utf8'
必须替换为 'binary'
或完全删除。
iv: forge.util.createBuffer(forge.util.decode64(ivBase64)),
payload: forge.util.createBuffer(forge.util.decode64(encryptedBase64))
此外,在 Java 代码的 getBytes()
中应指定编码,例如getBytes(StandardCharsets.UTF_8)
。如果不这样做,将使用 platform-dependent 默认编码,这意味着可以根据环境应用不同的编码。
通过这些更改,解密在 NodeJS 端进行。