views:

1085

answers:

2

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();
 }
+1  A: 

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?

Lasse V. Karlsen
I think he knows that AES does that, the question is about how to use the Java API.
skaffman
In order to know the correct unencrypted size after decrypting he should write out the original size to the stream.
Lasse V. Karlsen
+7  A: 

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).

caf
Awesome, thanks so much. That solved it. I was under the impression that if you only specified AES, you got ECB block mode and PCKS5Padding by default. Guess that's incorrect.
Wade Williams
the same applies to all AES engines, including those not in Java.
Cheeso