为什么使用 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 中随机获取代码样本。在开始实施之前,您需要了解密码学。不幸的是,您获取安全代码示例的机会几乎为零。