Search code examples
javaencryptioncryptographyaesbouncycastle

Why are these square symbols appended after decrypting with bouncy castle?


I have created a simple java method that encrypts and decrypts text using the bouncy castle library. Encryption works as expected but when I decrypt something I get these extra square symbols at the end:

console test

I think this might be something to do with padding but I've followed the example featured on bouncy castle's website, so I really can't understand why I would be getting this sort of output. Here is the code I am using:

[Main]

public static void main(String[] argv) {
    String ciphertext = "PlJR5pzbowsuzHIc9iTKHg==";
    String decrypted;
    CryptoCodec codec = new CryptoCodec();

    decrypted = codec.exec("AES", "xxxxooooxxxxoooo", ciphertext, false);

    System.out.println("Ciphertext: " + ciphertext);
    System.out.println("Decrypted: " + decrypted);
}

[CryptoCodec]

// Eod: (true) Encrypt or (false) decrypt.
public String exec(String algorithm, String key, String data, boolean eod) {

    // Using AESEngine();
    BlockCipher engine = CipherEngine.getBlockCipher(algorithm);

    BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(engine));

    byte[] keyBytes = key.getBytes(StandardCharsets.UTF_8);
    byte[] dataBytes;
    if(eod) {
        dataBytes = data.getBytes(StandardCharsets.UTF_8);
    } else {
        dataBytes = Base64.decode(data);
    }

    cipher.init(eod, new KeyParameter(keyBytes));

    byte[] outputText = new byte[cipher.getOutputSize(dataBytes.length)];
    int outputTextLen = cipher.processBytes(dataBytes, 0, dataBytes.length, outputText, 0);

    try {
        cipher.doFinal(outputText, outputTextLen);
    } catch (CryptoException err) {
        err.printStackTrace();
    }

    if(eod) {
        return new String(Base64.encode(outputText));
    } else {
        return new String(outputText);
    }
}

Please keep in mind I am still learning about cryptography and would love to hear any sort of explanation to why this may be happening. Thanks in advance.


Solution

  • During decryption cipher.getOutputSize(dataBytes.length) doesn't know how many bytes it will remove from padding (it doesn't even know that you're telling it about the last part of the data). So it tells you the maximum it could be.

    Your destination array is therefore larger than it needs to be, and you need to respect how much data got filled in.

    How do you know how much got filled in? Capture the return value from doFinal. What do you do with it then? Tell the String constructor when to stop reading.

    You then end up with something like

    try {
        outputTextLen += cipher.doFinal(outputText, outputTextLen);
    } catch (CryptoException err) {
        err.printStackTrace();
    }
    
    if(eod) {
        return new String(Base64.encode(outputText));
    } else {
        return new String(outputText, 0, outputTextLen);
    }
    

    Which also fixes your bug that if you encrypt 16 bytes of data right now you won't decrypt successfully.