encryption - Java (Cipher) 和 JavaScript (crypto-js) 之间的加密互操作
问题描述
我的任务是修复一个互操作加密算法,该算法从以前开始工作得非常好,但由于未知原因突然失控,没有人接触过这两种语言(Java 和 JS)的任何代码。
我不太熟悉密码学,所以我不知道寻找或使用什么可能的解决方案。任务基本上是把 Java 上的加密代码翻译成 JavaScript,这两者都将产生一个要通过 Java 解密的 Base64 字符串。
以下是使用 Java 和 JS 进行的加密以及在 Java 上的解密过程的代码片段:
Java 加密
public static String encryptMsg(String message) {
@SuppressLint("GetInstance") Cipher cipher = null;
try {
cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
byte[] cipherText = cipher.doFinal(message.getBytes(UTF_CHARSET));
return Base64.encodeToString(cipherText, Base64.DEFAULT);
} catch (NoSuchAlgorithmException | NoSuchPaddingException | BadPaddingException | IllegalBlockSizeException | InvalidKeyException e) {
e.printStackTrace();
} catch (NullPointerException e) {
//Do nothing, nothing to encrypt
}
return null;
}
JavaScript 加密
function encryptData(data, key) {
const options = {
mode: Crypto.mode.ECB,
padding: Crypto.pad.Pkcs7
}
const secret = Crypto.enc.Utf8.parse(key)
const encrypted = Crypto.AES.encrypt(data, secret, options)
return encrypted.ciphertext.toString(Crypto.enc.Base64)
}
Java解密
public static String decryptMsg(String base64cipherText) {
@SuppressLint("GetInstance") Cipher cipher = null;
try {
cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.DECRYPT_MODE, secret);
String decryptString = new String(cipher.doFinal(Base64.decode(base64cipherText, Base64.DEFAULT)), UTF_CHARSET);
return decryptString;
} catch (NoSuchAlgorithmException | NoSuchPaddingException | BadPaddingException | IllegalBlockSizeException | InvalidKeyException e) {
e.printStackTrace();
} catch (NullPointerException e) {
//Do nothing, nothing to decrypt
}
return null;
}
目前,结果null
在解密时使用 JavaScript 加密函数返回加密字符串,因此它可能正确加密(?)我不确定我在这里遗漏了什么或做错了什么......
解决方案
似乎您缺少 IV(初始化向量)。
真的不知道 IV 是什么,或者这里是否需要它,加密 Java 代码没有在任何地方说明它
IV 是一个初始化向量,允许重用密钥来加密多个消息(或块),请在使用时查看CBC 块模式。
我不确定 JavaScript API,但至少我可以用 Java 举个例子。你也可以看看我关于加密示例的博客
Java 加密
SecureRandom rnd = new SecureRandom();
byte[] iv = new byte[SYMMETRIC_BLOCK_SIZE / 8];
IvParameterSpec ivParamSpec = new IvParameterSpec(iv);
SecretKey symmetricKey = new SecretKeySpec(encryptionParams.getKey(), SYMMETRIC_KEY_ALG);
Cipher cipher = Cipher.getInstance(SYMMETRIC_CIPHER_NAME);
cipher.init(Cipher.ENCRYPT_MODE, symmetricKey, ivParamSpec);
byte[] encrypted = cipher.doFinal(encryptionParams.getPlaintext());
/* and encoded form can contain form of base64( IV + ciphertext ) */
对于 CBC 模式,IV 必须是随机的。如果您不指定 IVParameter,则会生成它,您可以从cipher.getIV();
. IV 可以是公开的,它通常放在密文之前,因为需要 IV 来解密密文本身。
Java解密
/* if IV is prepended before the ciphertext, it can be fetched as sub-array
of the decoded message */
IvParameterSpec ivParamSpec = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance(SYMMETRIC_CIPHER_NAME);
cipher.init(Cipher.DECRYPT_MODE, symmetricKey, ivParamSpec);
byte[] decrypted = cipher.doFinal(encryptionParams.getCiphertext());
在此示例中没有 Mac(包括消息验证码),您可以查看链接示例。
对于 JavaScript,您应该查看使用的 API,但原理保持不变(您也必须以某种方式生成、使用、传递和提供 IV)。这个博客似乎包含更完整的代码。
var iv = CryptoJS.lib.WordArray.random(128/8);
var encrypted = CryptoJS.AES.encrypt(msg, key, {
iv: iv,
padding: CryptoJS.pad.Pkcs7,
mode: CryptoJS.mode.CBC
});
推荐阅读
- c# - 从代码隐藏修改 DataTemplate 中条目的 Text 属性
- python - BeautifulSoup:获取显示“x 分钟前”的列的时间和日期
- phpstorm - Xdebug 在 CLI 和 Lando 环境中不起作用
- function - 将 Google Cloud Function Endpoint 隐藏在公司子域后面
- google-sheets-api - 基于一个单元格内的多个值提取数据的查询功能
- javascript - 我怎样才能把“” - 空格 - 在第七个字符?
- python - 计算连续 GPS 点之间的距离,并根据此距离降低 GPS 密度
- spacy - python -m spacy download en_core_web_sm 使用 spacy 3.0.3 失败
- huawei-mobile-services - 错误:使用HMS Map SDK 5.1时com.huawei.hms.maps.util包不存在
- python - Python C.Committ 在 SQLlite 中未被识别,错误仅在数据输入后在退出时显示