简体   繁体   English

Java - 为什么我的 AES 程序不加密/解密双引号?

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

I'm implementing a simple AES-128 encryption program using Java's Crypto library.我正在使用 Java 的 Crypto 库实现一个简单的 AES-128 加密程序。

Unfortunately, this doesn't work very well all the time.不幸的是,这并不能一直很好地工作。 Sometimes it happens that the double-quotes (") in the plaintext String are when encrypted and then decrypted, show up as in the decrypted string.有时会发生明文字符串中的双引号 (") 在加密然后解密时,在解密字符串中显示为 。

From what I found out, this character is &#xfffd (&#65533), which is a replacement character used by the UTF-8 decoder when it encounters an error.据我了解,这个字符是&#xfffd(&#65533),它是UTF-8解码器遇到错误时使用的替换字符

Thus, my question is why does this error occur, why only sometimes and how do I resolve it?因此,我的问题是为什么会发生此错误,为什么只是有时以及如何解决它?

Here's my code block for encryption and decryption:这是我用于加密和解密的代码块:

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;
    }

Here are some examples cases:以下是一些示例案例:

Case 1: Error caused案例一:错误导致

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?�

Case 2: No issue案例 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. 

I'm confident that the crypto stuff isn't relevant here;我相信加密的东西在这里不相关; rather, the problem must be in the round trip of String.getBytes() and new String(byte[]).相反,问题必须出在 String.getBytes() 和 new String(byte[]) 的往返过程中。 Your "Case 1: Error caused" involves non-ASCII curly quotes (whereas your "Case 2: No issue" uses regular ASCII quotes), so apparently String.getBytes() and new String(byte[]) on your system don't handle that character very well.您的“案例 1:导致错误”涉及非 ASCII 卷曲引号(而您的“案例 2:没有问题”使用常规 ASCII 引号),因此显然您的系统上的 String.getBytes() 和 new String(byte[]) 不很好地处理这个角色。 (Those methods are documented as using "the platform's default charset", and apparently your platform's default charset is one that doesn't support that character.) (这些方法被记录为使用“平台的默认字符集”,显然您平台的默认字符集不支持该字符。)

To fix this, I think all you need to do is switch from String.getBytes() to String.getBytes(Charset) and from new String(byte[]) to new String(byte[], Charset) , using StandardCharsets.UTF_8 as the charset in both cases.要解决此问题,我认为您需要做的就是使用StandardCharsets.UTF_8从 String.getBytes() 切换到String.getBytes(Charset)并从 new String(byte[]) 切换到new String(byte[], Charset)作为两种情况下的字符集。 (Or any other appropriate charset, but UTF-8 is the most common choice nowadays.) (或任何其他合适的字符集,但 UTF-8 是当今最常见的选择。)

So:所以:

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

and

            return new String(original, StandardCharsets.UTF_8);

The quote in your paste is not the standard ASCII ", but something else.您粘贴中的引号不是标准的 ASCII 字符,而是其他内容。

You have string-based keys and ivs and use UTF-8 to turn those into actual byte arrays.您有基于字符串的键和 ivs,并使用 UTF-8 将它们转换为实际的字节数组。 This is probably a mistake, you're reducing randomness a bit there, but not enough to be too worried about.这可能是一个错误,你在那里减少了一些随机性,但还不足以太担心。

However, for the actual payload, you don't do this - and that's where you should have.但是,对于实际的有效载荷,您不需要这样做 - 而这正是您应该拥有的地方。

It's not value.getBytes() , it's value.getBytes(StandardCharsets.UTF-8) , and not new String(original) , but new String(original, StandardCharsets.UTF_8) .它不是value.getBytes() ,它是value.getBytes(StandardCharsets.UTF-8) ,而不是new String(original) ,而是new String(original, StandardCharsets.UTF_8)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM