Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java cipher.doFinal() writing extra bytes

I'm implementing encryption / decryption using Java Cipher and AES. Everything is working well except that there's 5 extra bytes written on the call to doFinal(). So, I end up with a correctly decoded string with 5 extra bytes appended.

I believe the reason is that the entire block of 16-bytes is being written. I see 3 16-byte blocks written, including the last one. The input encrypted file is 64-bytes. The unencrypted text should be 43 bytes.

The documentation for doFinal indicates that it can return the number of bytes written to the output buffer. However, it's 0,16,16,16. I've tried every form of doFinal and update and get no change in behavior.

It kind of makes sense that it's writing out a full-block, since that's how most of these algorithms operate. However, if it's not going to tell me the size of the output data, how am I supposed to prevent excess data?

Should perhaps I be using another algorithm? AES256 is a requirement, but I wonder if a different block type or padding type might allow it to write the correct number of bytes.

Any guidance?

Snipped for (some) brevity:

decryptCipher = Cipher.getInstance("AES");
decryptCipher.init(Cipher.DECRYPT_MODE, aesKey);

Business part of the decryption routine.

    long bytesToRead = inputFile.length();

    while ((inLen = in.read(buffer)) > 0) {
        int bytesOut = 0;
        byte[] cryptBytes = null;
        int outLen = cipher.getOutputSize(inLen);
        cryptBytes = new byte[outLen];

        if (bytesToRead <= buffer.length) {
            try {
                bytesOut = cipher.doFinal(buffer, 0, inLen, cryptBytes, 0);
            } catch (ShortBufferException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        } else
            try {
                bytesOut = cipher.update(buffer, 0, inLen, cryptBytes, 0);
            } catch (ShortBufferException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        out.write(cryptBytes, 0, bytesOut);
        bytesToRead -= inLen;

    }
    try {
        out.flush();
        in.close();
        out.close();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
like image 416
wadesworld Avatar asked Aug 04 '09 07:08

wadesworld


2 Answers

You must specify a padding mechanism when you call Cipher.getInstance() - obviously it must be the same at both encryption and decryption time. eg:

decryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

Without a padding mechanism, the decryption side has no information on where the end of the plaintext is (within the last block).

like image 128
caf Avatar answered Nov 10 '22 23:11

caf


AES is a block cipher, naturally it's going to give you entire blocks, as will all block ciphers.

See the Wikipedia article on AES for more information.

You said you wanted it to output the "correct number of bytes". How have you decided what is the correct number of bytes?

like image 23
Lasse V. Karlsen Avatar answered Nov 11 '22 00:11

Lasse V. Karlsen