javascript - Java中的AES加密工作,但JavaScript中的解密不起作用?
问题描述
我正在尝试加密价值服务器端,然后从浏览器端解密。这是我用来加密的 Java 代码,它工作正常:
package aes;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
public class AesEncryption {
private static SecretKeySpec secretKey;
private static byte[] key;
public static void setKey(String myKey) {
MessageDigest sha = null;
try {
key = myKey.getBytes("UTF-8");
sha = MessageDigest.getInstance("SHA-1");
key = sha.digest(key);
key = Arrays.copyOf(key, 16);
secretKey = new SecretKeySpec(key, "AES");
}
catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
public static String encrypt(String strToEncrypt, String secret) {
try {
setKey(secret);
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
return Base64.getEncoder().encodeToString(cipher.doFinal(strToEncrypt.getBytes("UTF-8")));
}
catch (Exception e)
{
System.out.println("Error while encrypting: " + e.toString());
}
return null;
}
然后,我调用了一个 JavaScript 方法来解密加密值:
aesDecrypt(encryptedValue) {
console.log("TESTING ENCRYPTED VALUE : " , encryptedValue)
var bytes = CryptoJS.AES.decrypt(encryptedValue, secretAesKey, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
})
console.log("TESTING BYTES : " , bytes)
var originalValue = bytes.toString(CryptoJS.enc.Utf8);
console.log("TESTING ORIGINAL VALUE : " , originalValue)
return originalValue
}
在记录解密的每个步骤时,在尝试打印原始值时,它只是空白。我知道 encryptedValue 必须以与最初加密相同的方式转换回字节,然后必须用 UTF-8 编码才能返回原始字符串。我还能错过什么导致这种情况?
解决方案
CryptoJS 可以通过 SHA-1 导出密钥,例如:
var passphrase = '<your passphrase>';
var sha1Hash = CryptoJS.SHA1(passphrase); // Create SHA1 hash
var secretAesKey = CryptoJS.lib.WordArray.create(sha1Hash.words.slice(0, 16 / 4)); // Use the first 4 words (= 16 bytes) of the hash
使用 Java 代码生成的密文进行测试:
function aesDecrypt(encryptedValue) {
console.log("TESTING ENCRYPTED VALUE : " , encryptedValue);
var bytes = CryptoJS.AES.decrypt(
encryptedValue,
secretAesKey,
{
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
}
);
console.log("TESTING BYTES : " , bytes);
var originalValue = bytes.toString(CryptoJS.enc.Utf8);
console.log("TESTING ORIGINAL VALUE : " , originalValue);
return originalValue;
}
var passphrase = 'my secret passphrase';
var sha1Hash = CryptoJS.SHA1(passphrase)
var secretAesKey = CryptoJS.lib.WordArray.create(sha1Hash.words.slice(0, 16 / 4));
var ciphertext = 'hjC0d3sEGJ/3SBTPyV5RrbiIi5jCfhj9T2ZbeWNyBHqmCrVaKLYN94ouiMOz8d4x';
aesDecrypt(ciphertext);
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>
它正确地将密文解密为原始明文。
请注意,正如评论中所提到的,ECB 模式是不安全的,而且通过摘要从密码派生的密钥也是不安全的(即使它不会被破坏)。相反,应该使用可靠的密钥派生函数,如 Argon2 或 PBKDF2。
推荐阅读
- compiler-construction - 有人可以将伪代码解释为更简单的语言吗?
- css - 材料表单字段赋予日期选择器与其他字段相同的高度
- oracle - Oracle DB Remote directory
- javascript - How would I read the raw text from a txt file from discord chat on a web hosted bot
- sas - Percentile values Proc rank Sas
- c# - 无法使用 EF Core 播种数据库
- java - Why do I have to delete the calls to "super.doGet(req, resp)" and "super.doPost(req, resp)"?
- javascript - 如何在反应中从 json 构建 SQL 查询?
- c# - 使用 Mock 对异常 secario 进行单元测试
- c++ - C++17 向量类如何从参数包中推导出类型?