我有一个服务器在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);
控制台日志的结果是散列:e43df9b5a46b755ea8f1b4dd08265544加密值: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();
}
控制台的结果是散列:e43df9b5a46b755ea8f1b4dd08265544好加密值没有出现-我得到一个InvalidAlgorithmParameterException,说IV长度必须是16字节长。
谁能帮助我理解为什么MD5工作在JS上,而不是在JAVA上?我需要在Java中拥有与JS相同的加密值。
谢谢! !
很好,你的Java代码有几个问题。
我想指出的第一个事实是,每当我们将字节转换为十六进制字符串。十六进制字符串的长度将增加一倍。即16个字节将产生32个长度的等价十六进制字符串。
更不用说在您的Java代码中,您正在将某些固有的字节转换为十六进制字符串,并使用十六进制字符串的tobytes进行输入,这是没有意义的,因为这些不相同。这是不必要的转换开销(太不正确了)。
相反,我可以重写我的md5方法如下: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();
byte[] iv = new byte[16];
for (int x=0; x< 16;x++){
// this for loop need to be written as per your requirement.
iv[x]=byteArray[x];
}
return iv;
}
基本参考:如何转换字节数组十六进制字符串在Java?
AES:https://www.baeldung.com/java-aes-encryption-decryption
希望有帮助,谢谢。
我需要用户在HTML页面中输入凭据,然后用javascript对它们进行加密并将它们发送到服务器,在那里我需要用Java对它们进行解密。
请使用正确的TLS/SSL。请不要重新发明轮子。SSL将正确地加密客户机和服务器之间的所有通信。你自己不能做得更好。
提供的代码(Java和JS)有多个问题(从硬编码iv/key,没有cbc的完整性验证,…到可能不同的编码)。然而对于已定义的用例,它是完全不需要的。
InvalidAlgorithmParameterException
IV必须是128位(16字节)长。JS悄悄地和不幸地截断或零填充输入无效的长度。
md5 fn返回十六进制编码的摘要,其结果是32字节的值。当使用crypto时,总是使用字节数组(或JS缓冲区)并编码/解码为最终输入/输出的文本。
我写了一些关于加密基础知识的笔记。加密的难点在于所有的部分都必须存在并且合适。不加理解地复制/粘贴代码会给人一种错误的安全感。
我们只希望存储在DB中的凭证被正确加密。
注。为什么*****是人们写自己的十六进制编码/解码功能??(作业除外)