Java(服务器)和JS(客户端)之间的AES加密

snvhrwxg  于 2023-04-04  发布在  Java
关注(0)|答案(3)|浏览(163)

我有一个运行在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中得到的相同的加密值。
谢谢!

yvgpqqbh

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转换为字节时显式指定编码:

byte[] ivBytes = initVector.getBytes(StandardCharsets.UTF_8);
byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);

IvParameterSpec iv = new IvParameterSpec(ivBytes);
SecretKeySpec skeySpec = new SecretKeySpec(keyBytes, "AES");

这将确保在JavaScript和Java代码中使用UTF-8对键和IV进行编码。

fxnxkyjh

fxnxkyjh2#

好了,你的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;
    }

基本参考:How to convert a byte array to a hex string in Java?
AES参考:https://www.baeldung.com/java-aes-encryption-decryption
希望这有帮助,谢谢。

hc2pp10m

hc2pp10m3#

我发现了这个代码,在Javascript中加密,在Java中解密。它工作得很好,虽然我似乎不能做相反的事情。如果找到解决方案,我会在这里发布。

相关问题