我有一个运行在JAVA的服务器,我创建一个客户端与HTML和Javascript(关于这一点我不太了解)。服务器访问存储在数据库中的AES加密的登录凭据。我需要用户将凭据输入到HTML页面中,然后JavaScript对它们进行加密并将其发送到服务器,我需要在Java中解密它们。我在网上找到了很多线程,但无法解决我的问题:使用JS和Java加密产生不同的结果。
这是我的JavaScript代码。
var key = "0123456789ABCDEF";
function encrypt() {
const ivMd5Hash = CryptoJS.MD5(CryptoJS.enc.Utf8.parse(key));
console.log("Hash: "+ivMd5Hash)
const cipher = this.cipher(CryptoJS.enc.Utf8.parse(value), CryptoJS.enc.Utf8.parse(key), ivMd5Hash);
return cipher.ciphertext.toString();
}
function cipher(value, key, iv) {
const cipher = CryptoJS.AES.encrypt(value, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
keySize: 128,
padding: CryptoJS.pad.Pkcs7
});
return cipher;
}
console.log("Encrypted value: "+encrypt("testuser", key);
控制台日志结果为HASH:e43 df 9 b5 a46 b755 ea 8 f1 b4 dd 08265544加密值:fc88ab1f7821b9f8c5b46ab1d41250a2
现在是JAVA部分。
public class MainClass {
private static final String key = "0123456789ABCDEF";
private static String initVector = "";
public static void main(String[] args) throws Exception {
initVector=md5(key); // md5 is an external method, which works
System.out.println("HASH: "+initVector);
System.out.println("Encrypted value: "+encrypt("testuser"));
}
public static String encrypt(String value) {
try {
IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encrypted = cipher.doFinal(value.getBytes());
return Base64.encodeBase64String(encrypted);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
}
public static String md5(String str) {
MessageDigest messageDigest = null;
try {//from w w w . j a v a 2 s. c o m
messageDigest = MessageDigest.getInstance("MD5");
messageDigest.reset();
messageDigest.update(str.getBytes("UTF-8"));
} catch (NoSuchAlgorithmException e) {
System.out.println("NoSuchAlgorithmException caught!");
System.exit(-1);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
byte[] byteArray = messageDigest.digest();
StringBuffer md5StrBuff = new StringBuffer();
for (int i = 0; i < byteArray.length; i++) {
if (Integer.toHexString(0xFF & byteArray[i]).length() == 1)
md5StrBuff.append("0").append(
Integer.toHexString(0xFF & byteArray[i]));
else
md5StrBuff.append(Integer.toHexString(0xFF & byteArray[i]));
}
return md5StrBuff.toString();
}
控制台返回结果为HASH:e43 df 9 b5 a46 b755 ea 8 f1 b4 dd 08265544OK加密的值没有出现-我得到一个InvalidAlgorithmParameterException,说IV长度必须是16字节长。
有谁能帮我理解为什么MD5在JS上工作而在JAVA上不工作?我需要在Java中有我从JS中得到的相同的加密值。
谢谢!
3条答案
按热度按时间yvgpqqbh1#
看起来问题可能与密钥和初始化向量的编码有关(IV)。在JavaScript代码中,您使用
CryptoJS.enc.Utf8.parse()
来解析键和IV,这意味着输入字符串被解释为UTF-8
。然而,在Java代码中,您使用的是getBytes在一个实施例中,使用UTF-8(“UTF-8”)方法将密钥和IV转换为字节,该方法还假设输入字符串是UTF-8编码的。Java中getBytes()使用的默认编码可能与JavaScript中
CryptoJS.enc.Utf8.parse()
使用的默认编码不同,这可能导致键和IV使用不同的字节数组。为了确保一致的结果,您可以尝试在Java代码中将key和IV转换为字节时显式指定编码:
这将确保在JavaScript和Java代码中使用UTF-8对键和IV进行编码。
fxnxkyjh2#
好了,你的Java代码有一些问题。
我想指出的第一个事实是,每当我们将字节转换为十六进制字符串时,十六进制字符串的长度将加倍。即16个字节将产生32个长度的十六进制字符串。
更不用说在你的Java代码中,你正在将一些固有的字节转换为十六进制字符串,并使用十六进制字符串的tobytes输入,这是没有意义的,因为它们是不一样的。这是不必要的转换开销(这太不正确了)。
相反,我可以重写我的md5方法如下:
基本参考:How to convert a byte array to a hex string in Java?
AES参考:https://www.baeldung.com/java-aes-encryption-decryption
希望这有帮助,谢谢。
hc2pp10m3#
我发现了这个代码,在Javascript中加密,在Java中解密。它工作得很好,虽然我似乎不能做相反的事情。如果找到解决方案,我会在这里发布。