javaencryptioncryptographypaddingblock-cipher

What exactly does the "NoPadding" parameter do in the Cipher class?


Java's Cipher class supports the transformations listed there. Among them are several NoPadding variants:

I assumed at first that "padding" here meant the method used to fill the last plaintext block, if the plaintext's size isn't a multiple of the cipher's block size.

But in that case, how can a block cipher mode like ECB or CBC be used with "no padding"? Suppose that we use AES/ECB/NoPadding to encrypt a 250-bit message. The first block of the plaintext is obviously the first 128 bits of the message. What are the last 6 bits of the second plaintext block?


Solution

  • Well, first of all, you cannot feed Cipher - in any mode - a 250 bit message directly. The reason for that is that - like in most runtimes - the byte is the smallest amount of data that you can process. If you want to encode 250 bits you will have to think of an encoding of those bits in bytes (e.g. by indicating the bits in the final byte that you don't use, as performed for the value encoding of a DER encoded ASN.1 defined BIT STRING).


    DER BIT STRING example for just 11 bits set to 1:

    05 FF E0
    

    here there are 5 unused bits in the final byte (which are set to value 0). So the first byte is simply sacrificed to indicate this fact - it's not part of the value.


    Second, even if the input would be a multiple of 8 bits, then you would still not be able to encrypt using NoPadding for ECB or CBC mode unless the input itself is already a multiple of the block size. If you specify NoPadding then indeed no bytes are added (not even 00 valued bytes) so you'll get an IllegalBlockSizeException if the plaintext size is not a multiple of the block size (16 bytes for AES and 8 bytes for DES & DES-EDE).

    The plaintext size is the amount of input bytes provided to the update and doFinal methods together. The bytes for the blocks before the last one will be buffered where required - only the final count matters.


    From the Cipher#doFinal documentation:

    throws:

        ...
        IllegalBlockSizeException - if this cipher is a block cipher, no padding has been requested (only in encryption mode), and the total input length of the data processed by this cipher is not a multiple of block size; or if this encryption algorithm is unable to process the input data provided.
        ...

    Note that this is a this is a terrible description in my opinion: during decryption this exception will be thrown by doFinal regardless of the padding used (again, only for ECB and CBC modes) if the size is not a multiple of the block size. The unpadding only happens after decryption by the block cipher and mode of operation after all.

    Of course, the output of ECB & CBC mode during encryption should always be a multiple of the block size, so that would mean that the ciphertext was truncated or otherwise altered before decryption.


    For GCM padding is not required (CTR mode encryption is used within), so NoPadding is the only realistic option, and any amount of data goes - but again the smallest element to be encrypted by Cipher is a byte. Even though the GCM algorith is specified in bits rather than bytes, this implementation doesn't support it.