简体   繁体   English

为什么使用 BouncyCastle 解密的文本与输入文本有点不同?

[英]Why with BouncyCastle decrypted text is a bit different from input text?

I found on Google this code for encrypt/decrypt a string in Java:我在 Google 上找到了用于加密/解密 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);

And this is the output (screenshot because I can't copy-paste some characters): output screenshot这是 output (截图因为我不能复制粘贴一些字符): output screenshot

My question is: Why the first input "test" is different from the second (decrypted) "test"?我的问题是:为什么第一个输入“测试”与第二个(解密的)“测试”不同? I need this code to encrypt a password and save it on a TXT file and then read this encrypted password from the TXT file and decrypt it.. But if these two outputs are different I can't do this.我需要此代码来加密密码并将其保存在 TXT 文件中,然后从 TXT 文件中读取此加密密码并对其进行解密。但是如果这两个输出不同,我将无法执行此操作。 Second question: Is it possible to exclude ";"第二个问题:是否可以排除“;” from the encrypted text?从加密的文本? Can someone help me, please?有人能帮助我吗? Thanks!谢谢!

If you read the documentation for getOutputSize() then you will see that it returns the maximum amount of plaintext to expect.如果您阅读getOutputSize()的文档,那么您将看到它返回预期的最大明文量。 The cipher instance cannot know how much padding is added, so it guesses high. cipher实例无法知道添加了多少填充,因此它猜测很高。 You will have to resize the byte array when you are using ECB or CBC mode (or any other non-streaming mode).当您使用 ECB 或 CBC 模式(或任何其他非流模式)时,您必须调整字节数组的大小。

System.out.println(ctLength);

As you can see, ctLength does have the correct size.如您所见, ctLength确实具有正确的大小。 Use Arrays.copyOf(plainText, ptLength) to get the right number of bytes, or use the four parameter String constructor ( new String(plainText, 0, ptLength, StandardCharsets.UTF_8) ) in case you're just interested in the string.使用Arrays.copyOf(plainText, ptLength)获取正确的字节数,或者使用四参数String构造函数( new String(plainText, 0, ptLength, StandardCharsets.UTF_8) ),以防您只对字符串感兴趣。

The ciphertext consists of random characters.密文由随机字符组成。 It actually depends on your standard character set what you see on the screen.它实际上取决于您在屏幕上看到的标准字符集。 If you really need text, then you can base 64 encode the ciphertext.如果你真的需要文本,那么你可以对密文进行base 64编码。


ECB mode encryption is not suitable to encrypt strings. ECB 模式加密不适合加密字符串。 You should try and use a different mode that includes setting / storing an IV.您应该尝试使用不同的模式,包括设置/存储 IV。

I'd use new String(StandardCharsets.UTF_8) and String#getBytes(StandardCharsets.UTF_8) to convert to and from strings.我会使用new String(StandardCharsets.UTF_8)String#getBytes(StandardCharsets.UTF_8)来转换字符串。 If you don't specify the character set then it uses the system default character set, and that means decrypting your passwords won't work on all systems.如果您不指定字符集,则它使用系统默认字符集,这意味着解密您的密码将无法在所有系统上工作。 The allowed characters also differ with Linux & Android defaulting on UTF-8 while Java SE on Windows (still?) defaults to the Windows-1252 (extended Western-Latin) character set. The allowed characters also differ with Linux & Android defaulting on UTF-8 while Java SE on Windows (still?) defaults to the Windows-1252 (extended Western-Latin) character set.

There is absolutely no need to use the Bouncy Castle provider for AES encryption (the compatible padding string is "PKCS5Padding" ).绝对不需要使用 Bouncy Castle 提供程序进行 AES 加密(兼容的填充字符串是"PKCS5Padding" )。


Please don't grab random code samples from Google.请不要从 Google 获取随机代码示例。 You need to understand cryptography before you start implementing it.在开始实施之前,您需要了解密码学。 The chances that you grab a secure code sample is practically zero unfortunately.不幸的是,您获取安全代码示例的机会几乎为零。

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

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