Java - 为什么我的 AES 程序不是 encrypting/decrypting 双引号?

Java - Why is my AES program not encrypting/decrypting double quotes?

我正在使用 Java 的加密库实现一个简单的 AES-128 加密程序。

不幸的是,这并不是一直都有效。有时会出现明文String中的双引号(")加密后解密,在解密后的字符串中显示为�

据我了解,这个字符是�(�),是UTF-8解码器遇到错误时使用的替换字符 .

所以,我的问题是为什么会出现这个错误,为什么只是有时出现,我该如何解决?

这是我的加密和解密代码块:

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.getEncoder().encodeToString(encrypted);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

    public static String decrypt(String encrypted)
    {
        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.DECRYPT_MODE, skeySpec, iv);
            byte[] original = cipher.doFinal(Base64.getDecoder().decode(encrypted));

            return new String(original);
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return null;
    }

以下是一些示例案例:

案例一:错误导致

Enter Plaintext: had no pictures or conversations in it, “and what is the use of a book,” thought Alice “without pictures or conversations?”
Encrypted String: UgapiW5aYIKkoKkyeHvvFlgf8mCIq1AopmCtYGiJ23eNILNn1OXtM4enEvB5Kt1imNmynyHCCjLbbjB7TV0sq2F3Iz+YUehOw50gje6IMj8fpaEracq1NvZQXSH5T8fyBtAUH3weU5FE5vr3dYmwTSGUxNR2gaRV6MV7vmcEuIz7A5MLnKjsb2+1Sya+l/k2
Enter Ciphertext: UgapiW5aYIKkoKkyeHvvFlgf8mCIq1AopmCtYGiJ23eNILNn1OXtM4enEvB5Kt1imNmynyHCCjLbbjB7TV0sq2F3Iz+YUehOw50gje6IMj8fpaEracq1NvZQXSH5T8fyBtAUH3weU5FE5vr3dYmwTSGUxNR2gaRV6MV7vmcEuIz7A5MLnKjsb2+1Sya+l/k2
After decryption: had no pictures or conversations in it, �and what is the use of a book,� thought Alice �without pictures or conversations?�

案例 2:没有问题

Enter Plaintext: Hello there, "Camera-man". He's sitting now. 
Encrypted String: jb2QJ5nLQCjGKw6l2q9GnX6jgTJVGWn6LiVRfE5oRT7WT7vYNejKPHIhgorbfaob
Enter Ciphertext: jb2QJ5nLQCjGKw6l2q9GnX6jgTJVGWn6LiVRfE5oRT7WT7vYNejKPHIhgorbfaob
After decryption: Hello there, "Camera-man". He's sitting now. 

我相信加密的东西在这里不相关;相反,问题一定出在 String.getBytes() 和 new String(byte[]) 的往返过程中。您的“案例 1:导致错误”涉及 non-ASCII 大引号(而您的“案例 2:无问题”使用常规 ASCII 引号),因此显然 String.getBytes() 和 new String(byte[])您的系统不能很好地处理该字符。 (这些方法被记录为使用“平台的默认字符集”,显然您平台的默认字符集不支持该字符。)

要解决此问题,我认为您需要做的就是在两种情况下将字符集从 String.getBytes() 切换为 String.getBytes(Charset) and from new String(byte[]) to new String(byte[], Charset), using StandardCharsets.UTF_8。 (或任何其他合适的字符集,但 UTF-8 是当今最常见的选择。)

所以:

            byte[] encrypted = cipher.doFinal(
                value.getBytes(StandardCharsets.UTF_8));

            return new String(original, StandardCharsets.UTF_8);

您粘贴中的引号不是标准的 ASCII ",而是其他内容。

您有 string-based 键和 ivs,并使用 UTF-8 将它们转换为实际的字节数组。这可能是一个错误,你在那里降低了一点随机性,但还不足以让你太担心。

但是,对于实际有效载荷,您不需要这样做 - 而那是您应该这样做的地方。

不是value.getBytes(),是value.getBytes(StandardCharsets.UTF-8),也不是new String(original),而是new String(original, StandardCharsets.UTF_8)