Java-为什么我的AES程序不加密/解密双引号?
我正在使用Java的加密库实现一个简单的AES-128加密程序 不幸的是,这并不是一直都很有效。有时,明文字符串中的双引号(“)在加密然后解密时显示为� 在解密的字符串中 据我所知,这个字符是(�),它是UTF-8解码器遇到错误时使用的替换字符 因此,我的问题是,为什么会发生这种错误,为什么只是偶尔发生,以及如何解决它 这是我的加密和解密代码块:Java-为什么我的AES程序不加密/解密双引号?,java,encoding,utf-8,cryptography,aes,Java,Encoding,Utf 8,Cryptography,Aes,我正在使用Java的加密库实现一个简单的AES-128加密程序 不幸的是,这并不是一直都很有效。有时,明文字符串中的双引号(“)在加密然后解密时显示为� 在解密的字符串中 据我所知,这个字符是(�),它是UTF-8解码器遇到错误时使用的替换字符 因此,我的问题是,为什么会发生这种错误,为什么只是偶尔发生,以及如何解决它 这是我的加密和解密代码块: public static String encrypt(String value) { try {
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.
我相信加密内容在这里不相关;相反,问题一定是在String.getBytes()和new String(byte[])的往返过程中。您的“案例1:错误导致”包含非ASCII卷曲引号(而您的“案例2:无问题”使用常规ASCII引号),因此显然是String.getBytes()和new String(byte[])在您的系统上,无法很好地处理该字符(这些方法被记录为使用“平台的默认字符集”,显然您的平台的默认字符集不支持该字符) 要解决这个问题,我认为您需要做的就是从String.getBytes()切换到新字符串(byte[]),并从新字符串(byte[])切换到,在这两种情况下都用作字符集(或任何其他合适的字符集,但UTF-8是当今最常见的选择) 因此:
byte[]encrypted=cipher.doFinal(
value.getBytes(StandardCharsets.UTF_8));
及
返回新字符串(原始,StandardCharsets.UTF_8);
粘贴中的引号不是标准ASCII”,而是其他内容
您有基于字符串的键和IV,并使用UTF-8将它们转换为实际的字节数组。这可能是一个错误,你减少了一点随机性,但这还不足以让你太担心
然而,对于实际的有效载荷,您不需要这样做,而这正是您应该做的
它不是
value.getBytes()
,而是value.getBytes(StandardCharsets.UTF-8)
,也不是new String(original)
,而是new String(original,StandardCharsets.UTF_8)
,我确信加密的东西在这里不相关;相反,问题一定是在value.getBytes()
和新字符串(原始)
的往返过程中。“案例1:错误导致”和“案例2:无问题”之间的区别在于案例1涉及非ASCII卷曲引号。作为更好地理解这个问题的第一步,我建议循环使用value.tocharray()
并将字符打印为整数(最好是十六进制),然后对value.getBytes()
执行同样的操作。你完全正确!这两个双引号是不同的。案例1中的UNICODE值为8220,而案例2中的UNICODE值为ASCII 34。我从另一个来源复制了卷曲引用,这就是问题的原因。现在我想我的问题是,我能做些什么来解释这一点呢?有没有办法自动将非ASCII双引号更改为ASCII双引号,并对其他此类字符执行相同操作?