简体   繁体   中英

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:

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

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. 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. The cipher instance cannot know how much padding is added, so it guesses high. You will have to resize the byte array when you are using ECB or CBC mode (or any other non-streaming mode).

System.out.println(ctLength);

As you can see, ctLength does have the correct size. 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.

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.


ECB mode encryption is not suitable to encrypt strings. You should try and use a different mode that includes setting / storing an IV.

I'd use new String(StandardCharsets.UTF_8) and String#getBytes(StandardCharsets.UTF_8) to convert to and from strings. 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.

There is absolutely no need to use the Bouncy Castle provider for AES encryption (the compatible padding string is "PKCS5Padding" ).


Please don't grab random code samples from Google. You need to understand cryptography before you start implementing it. The chances that you grab a secure code sample is practically zero unfortunately.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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