为什么使用 BouncyCastle 解密的文本与输入文本有点不同?
Why with BouncyCastle decrypted text is a bit different from input text?
我在 Google 上找到 encrypt/decrypt Java 中字符串的代码:
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
byte[] input = "test".getBytes();
byte[] keyBytes = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 };
SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
System.out.println(new String(input));
// encryption pass
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] cipherText = new byte[cipher.getOutputSize(input.length)];
int ctLength = cipher.update(input, 0, input.length, cipherText, 0);
ctLength += cipher.doFinal(cipherText, ctLength);
System.out.println(new String(cipherText));
System.out.println(ctLength);
// decryption pass
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] plainText = new byte[cipher.getOutputSize(ctLength)];
int ptLength = cipher.update(cipherText, 0, ctLength, plainText, 0);
ptLength += cipher.doFinal(plainText, ptLength);
System.out.println(new String(plainText));
System.out.println(ptLength);
这是输出(截图因为我不能复制粘贴一些字符):
output screenshot
我的问题是:
为什么第一个输入“测试”与第二个(解密的)“测试”不同?
我需要此代码来加密密码并将其保存在 TXT 文件中,然后从 TXT 文件中读取此加密密码并对其进行解密。
但如果这两个输出不同,我就不能这样做。
第二个问题:
是否可以排除“;”来自加密文本?
有谁可以帮助我吗?谢谢!
如果您阅读 getOutputSize()
的文档,您会发现它 returns 是预期的最大明文数量。 cipher
实例无法知道添加了多少填充,所以它猜测高。当您使用 ECB 或 CBC 模式(或任何其他 non-streaming 模式)时,您必须调整字节数组的大小。
System.out.println(ctLength);
如您所见,ctLength
的大小确实正确。使用 Arrays.copyOf(plainText, ptLength)
获取正确的字节数,或者使用四参数 String
构造函数 (new String(plainText, 0, ptLength, StandardCharsets.UTF_8)
),以防您只对字符串感兴趣。
密文由随机字符组成。它实际上取决于您在屏幕上看到的标准字符集。如果你真的需要文本,那么你可以对密文进行base 64编码。
ECB 模式加密不适合加密字符串。您应该尝试使用不同的模式,包括设置/存储 IV。
我会使用 new String(StandardCharsets.UTF_8)
和 String#getBytes(StandardCharsets.UTF_8)
来转换字符串。如果您不指定字符集,那么它将使用系统默认字符集,这意味着解密您的密码将无法在所有系统上运行。允许的字符也不同,Linux 和 Android 默认为 UTF-8,而 Java SE 在 Windows(还是?)默认为 Windows-1252(扩展 Western-Latin) 字符集。
完全不需要使用Bouncy Castle提供程序进行AES加密(兼容的填充字符串是"PKCS5Padding"
)。
请不要从 Google 中随机获取代码样本。在开始实施之前,您需要了解密码学。不幸的是,您获取安全代码示例的机会几乎为零。
我在 Google 上找到 encrypt/decrypt Java 中字符串的代码:
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
byte[] input = "test".getBytes();
byte[] keyBytes = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 };
SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
System.out.println(new String(input));
// encryption pass
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] cipherText = new byte[cipher.getOutputSize(input.length)];
int ctLength = cipher.update(input, 0, input.length, cipherText, 0);
ctLength += cipher.doFinal(cipherText, ctLength);
System.out.println(new String(cipherText));
System.out.println(ctLength);
// decryption pass
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] plainText = new byte[cipher.getOutputSize(ctLength)];
int ptLength = cipher.update(cipherText, 0, ctLength, plainText, 0);
ptLength += cipher.doFinal(plainText, ptLength);
System.out.println(new String(plainText));
System.out.println(ptLength);
这是输出(截图因为我不能复制粘贴一些字符): output screenshot
我的问题是: 为什么第一个输入“测试”与第二个(解密的)“测试”不同? 我需要此代码来加密密码并将其保存在 TXT 文件中,然后从 TXT 文件中读取此加密密码并对其进行解密。 但如果这两个输出不同,我就不能这样做。 第二个问题: 是否可以排除“;”来自加密文本? 有谁可以帮助我吗?谢谢!
如果您阅读 getOutputSize()
的文档,您会发现它 returns 是预期的最大明文数量。 cipher
实例无法知道添加了多少填充,所以它猜测高。当您使用 ECB 或 CBC 模式(或任何其他 non-streaming 模式)时,您必须调整字节数组的大小。
System.out.println(ctLength);
如您所见,ctLength
的大小确实正确。使用 Arrays.copyOf(plainText, ptLength)
获取正确的字节数,或者使用四参数 String
构造函数 (new String(plainText, 0, ptLength, StandardCharsets.UTF_8)
),以防您只对字符串感兴趣。
密文由随机字符组成。它实际上取决于您在屏幕上看到的标准字符集。如果你真的需要文本,那么你可以对密文进行base 64编码。
ECB 模式加密不适合加密字符串。您应该尝试使用不同的模式,包括设置/存储 IV。
我会使用 new String(StandardCharsets.UTF_8)
和 String#getBytes(StandardCharsets.UTF_8)
来转换字符串。如果您不指定字符集,那么它将使用系统默认字符集,这意味着解密您的密码将无法在所有系统上运行。允许的字符也不同,Linux 和 Android 默认为 UTF-8,而 Java SE 在 Windows(还是?)默认为 Windows-1252(扩展 Western-Latin) 字符集。
完全不需要使用Bouncy Castle提供程序进行AES加密(兼容的填充字符串是"PKCS5Padding"
)。
请不要从 Google 中随机获取代码样本。在开始实施之前,您需要了解密码学。不幸的是,您获取安全代码示例的机会几乎为零。