【问题标题】:Java - Why is my AES program not encrypting/decrypting double quotes?Java - 为什么我的 AES 程序不加密/解密双引号?
【发布时间】:2020-10-08 04:51:15
【问题描述】:

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

不幸的是,这并不总是很好。有时会发生明文字符串中的双引号(“)在加密然后解密时,在解密的字符串中显示为�。

据我了解,这个字符是�(�),是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;
    }

以下是一些示例案例:

案例 1:导致错误

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. 

【问题讨论】:

  • 我相信加密的东西在这里不相关;相反,问题一定出在value.getBytes()new String(original) 的往返过程中。您的“案例 1:导致错误”和“案例 2:没有问题”之间的区别在于案例 1 涉及非 ASCII 大引号。作为更好地理解问题的第一步,我建议循环 value.toCharArray() 并将字符打印为整数(最好是十六进制),然后对 value.getBytes() 执行相同的操作。
  • 你完全正确!两个双引号是不同的。案例 1 中的 UNICODE 值为 8220,而案例 2 中的那个是 ASCII 34。我从不同的来源复制了大引号,这就是导致问题的原因。现在我想我的问题是,我能做些什么来解决这个问题?有没有办法自动将非 ASCII 双引号更改为 ASCII 双引号并对其他此类字符执行相同操作?

标签: java encoding utf-8 cryptography aes


【解决方案1】:

您粘贴中的引用不是标准的 ASCII ",而是别的东西。

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

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

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

【讨论】:

    【解决方案2】:

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

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

    所以:

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

                return new String(original, StandardCharsets.UTF_8);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-03
      • 1970-01-01
      • 2013-04-19
      • 2019-10-27
      • 1970-01-01
      相关资源
      最近更新 更多