Reputation: 31
I am doing AES CBC decryption in java using javax.crypto . I am using the following Cipher class methods:
public final void init (int opmode, Key key, AlgorithmParameters params)
method for initialization,final int update(byte[] input, int inputOffset, int inputLen, byte[] output)
method for decrypting the data,final int doFinal(byte[] output, int outputOffset)
method to finish the decryption.My query is this: Can I assume that the size of the data returned to me by the doFinal
call would always be less than or equal to the AES Block Size? The documentation describes the doFinal method as:
“Finishes a multi-part transformation (encryption or decryption). Processes any bytes that may have been buffered in previous update calls. The final transformed bytes are stored in the output buffer.”
But it nowhere says that the output buffer would contain at most one block of data. Though I understand that this is the general behaviour of AES APIs, and this is the behaviour my code has exhibited till now, but would this assumption always hold?
Upvotes: 3
Views: 7969
Reputation: 103807
In general (as in, in the context of the Cipher
class) I don't believe it would be safe to assume this. As per the javadocs for that doFinal
method:
If the output buffer is too small to hold the result, a ShortBufferException is thrown. In this case, repeat this call with a larger output buffer. Use getOutputSize to determine how big the output buffer should be.
So if you're allocating the output buffer "near" the point where you call the doFinal method, then it would make sense to call getOutputSize
and allocate an appropriately-sized buffer. Job done.
On the other hand, if you're passing in a buffer from "far away" that was created to be exactly the block size, you might be in more trouble. It would be perfectly legal (at least, according to the public interface of the Java class) for a Cipher implementation to return an output larger than the block size, so long as the getOutputSize method returns the appropriate size.
In fact, if you're doing CBC decryption, doesn't that require you to pass in all of the blocks to the update
method? In which case, you should get the full plaintext output back from doFinal
, not just a single block?
Upvotes: 3
Reputation: 74412
Generally speaking, it is not safe to assume that buffering is for one block only; and when you look at the details, you may see that it depends on the type of padding. With the usual "PKCS#5" padding, at least one byte and at most n bytes (for blocks of size n) are added, so the decryption system may limit itself to n bytes of buffering. Some other types of padding are a bit more complex, e.g. CTS requires 2n bytes of buffering. The Java cryptographic layer does not seem to support CTS right now, but this may be added in a future version.
Cipher.getOutputSize(len)
will give you the maximum output size, given len
additional input bytes. The returned value may be somewhat larger than what will be actually returned, especially with decryption, since it depends on what padding bytes will be actually found upon decryption.
What is safe to assume is that the total decrypted message length is no longer than the total encrypted message length (symmetric encryption does not involve data compression). So you may maintain two counters, one for the input data bytes (the encrypted blocks) and one for the obtained output data bytes; the difference will be a maximum bound for what can be obtained from the doFinal()
. But that's what getOutputSize()
does anyway.
Upvotes: 0