首页 > 解决方案 > IDE 和可运行 JAR 之间的 Java 字符串解码不同

问题描述

在我的程序中,我加密一个字符串并再次解密它。当我在 IntelliJ 中运行它时,它工作正常,但是当我构建一个 jar 时,某些字符无法正确解密。例如“ä”变成“ä”。我了解到当文本编码为 UTF-8 并解码为 ISO 8859-1 时会发生这种情况。(但我的文件已经编码为 UTF-8)

谁能解释为什么在 IntelliJ 中运行程序和将其作为 jar 运行之间存在加密/解码差异?

package main;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Arrays;
import java.util.Base64;

public class Main {

    public static void main(String[] args) throws Exception {
        SecretKeySpec password = createKey("safePassword");

        String message = "hello ä ö ü ß";

        String encryptedMessage = encrypt(message, password);
        //this output is the same in IntelliJ and as a jar
        System.out.println(encryptedMessage);

        byte[] decryptedBytes = decrypt(encryptedMessage, password);
        //this output gets messed up when I run it as a jar but not in Intellij
        System.out.println(new String(decryptedBytes));
        //this output works both ways
        System.out.println(new String(decryptedBytes, StandardCharsets.UTF_8));
    }

    public static String encrypt(String message, SecretKeySpec key) throws Exception {
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.ENCRYPT_MODE, key);
        byte[] encrypted = cipher.doFinal(message.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(encrypted);
    }

    public static byte[] decrypt(String encryptedMessage, SecretKeySpec key) throws Exception {
        byte[] message = Base64.getDecoder().decode(encryptedMessage);
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.DECRYPT_MODE, key);
        return cipher.doFinal(message);
    }

    public static SecretKeySpec createKey(String key) throws Exception {
        byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
        MessageDigest sha = MessageDigest.getInstance("SHA-256");
        keyBytes = sha.digest(keyBytes);
        keyBytes = Arrays.copyOf(keyBytes, 16);
        return new SecretKeySpec(keyBytes, "AES");
    }

}

IntelliJ 中的输出:

8nno4HGKG4/Ni/Sxun+s3roOAaav+eXT4kd0ivgZFBA=
hello ä ö ü ß
hello ä ö ü ß

罐子的输出:

8nno4HGKG4/Ni/Sxun+s3roOAaav+eXT4kd0ivgZFBA=
hello ä ö ü �
hello ä ö ü ß

标签: javastringintellij-ideacharacter-encoding

解决方案


    System.out.println(new String(decryptedBytes));

您的“字节”是 UTF-8 表示。

上面的行使用平台标准字符集构造了一个解释字节的字符串,它不一定是 UTF-8。

因此生成的字符串是垃圾。

文档链接


推荐阅读