AES/CBC 和 AES/ECB 加密后的数据大小

我想知道后 AES 加密数据的大小,以便我可以避免缓冲我的后 AES 数据(在磁盘或内存)主要是为了知道大小。

我使用128位 AES 和 javax.crypto.Cipherjavax.crypto.CipherInputStream进行加密。

使用不同输入大小执行的一些测试表明,按以下方式计算的加密后大小是正确的:

long size = input_Size_In_Bytes;
long post_AES_Size = size + (16 - (size % 16));

但我不确定上述公式是否适用于所有可能的输入大小。

有没有一种方法可以在应用 AES 加密后计算数据的大小-事先不必缓冲加密的数据(在磁盘或内存中) ,以了解其后加密的大小?

103900 次浏览

The AES cipher always works on 16-byte (128-bit) blocks. If the number of input bytes is not an exact multiple of 16, it is padded. That's why 16 appears to be the "magic number" in your calculation. What you have should work for all input sizes.

AES, as a block cipher, does not change the size. The input size is always the output size.

But AES, being a block cipher, requires the input to be multiple of block size (16 bytes). For this, padding schemes are used like the popular PKCS5. So the answer is that the size of your encrypted data depends on the padding scheme used. But at the same time all known padding schemes will round up to the next module 16 size (size AES has a 16 bytes block size).

AES works in 128-bit (16 bytes) blocks and converts cleartext blocks into cyphertext blocks of the same length. It pads the last block if it is shorter than 16 bytes, so your formula looks correct.

It depends on the mode in which you use AES. What you have is accurate for most of the block oriented modes, such as ECB and CBC. OTOH, in CFB mode (for one example) you're basically just using AES to produce a stream of bytes, which you XOR with bytes of the input. In this case, the size of the output can remain the size of the input rather than being rounded up to the next block size as you've given above.

AES has a fixed block size of 16-bytes regardless key size. Assuming you use PKCS 5/7 padding, use this formula,

 cipherLen = (clearLen/16 + 1) * 16;

Please note that if the clear-text is multiple of block size, a whole new block is needed for padding. Say you clear-text is 16 bytes. The cipher-text will take 32 bytes.

You might want to store IV (Initial Vector) with cipher-text. In that case, you need to add 16 more bytes for IV.

There are approaches to storing encrypted information which avoid the need for any padding provided the data size is at least equal to the block size. One slight difficulty is that if the data size is allowed to be smaller than the block size, and if it must be possible to reconstruct the precise size of the data, even for small blocks, the output must be at least one bit larger than the input, [i]regardless[/i] of the data size.

To understand the problem, realize that there are 256^N possible files that are N bytes long, and the number of possible files that are no longer than N bytes long is 256^N plus the number of possible files that are no longer than N-1 bytes long (there is one possible file that's zero bytes long, and 257 possible files that are no longer than one byte long).

If the block size is 16 bytes, there will be 256^16 + 256^14 + 256^13 etc. possible input files that are no more than 16 bytes long, but only 256^16 possible output files that are no more than 16 bytes long (since output files can't be shorter than 16 bytes). So at least some possible 16-byte input files must grow. Suppose they would become 17 bytes. There are 256^17 possible seventeen-byte output files; if any of those are used to handle inputs of 16 bytes or less, there won't be enough available to handle all possible 17-byte input files. No matter how big the input can get, some files of that size or larger must grow.

Generally speaking, for a block cipher encryption:

CipherText = PlainText + Block - (PlainText MOD Block)

ciphertext size is computed as the size of the plaintext extended to the next block. If padding is used and the size of the plaintext is an exact multiple of the block size, one extra block containing padding information will be added.

AES uses block size of 16 bytes, which produces:

CipherText = PlainText + 16 - (PlainText MOD 16)

Source: http://www.obviex.com/articles/CiphertextSize.pdf

Note:

  1. CipherText and PlainText represent the size of the cipher text and the size of the plain text accordingly.

If your input length is smaller than max size of int you could use Cipher.getOutputSize(int)

long post_AES_Size = size + (16 - (size % 16));


cipherLen = (clearLen/16 + 1) * 16

what @zz-coder and @OP mentioned are same.

int(clearLen/16) + 1) * 16
= ((clearLen - clearLen % 16) / 16 + 1) * 16
= clearLen - clearLen % 16 + 16;
= clearLen + (16  - clearLen % 16)