[ Team LiB ] Previous Section Next Section

5.11 Manually Adding and Checking Cipher Padding

5.11.1 Problem

You want to add padding to data manually, then check it manually when decrypting.

5.11.2 Solution

There are many subtle ways in which padding can go wrong, so use an off-the-shelf scheme, such as PKCS block cipher padding.

5.11.3 Discussion

Padding is applied to plaintext; when decrypting, you must check for proper padding of the resulting data to determine where the plaintext message actually ends.

Generally, it is not a good idea to add padding yourself. If you're using a reasonably high-level abstraction, padding will be handled for you. In addition, padding often isn't required, for example, when using a stream cipher or one of many common block cipher modes (including CWC, CTR, CCM, OFB, and CFB).

Because ECB mode really shouldn't be used for stream-based encryption, the only common case where padding is actually interesting is when you're using CBC mode.

If you are in a situation where you do need padding, we recommend that you use a standard scheme. There are many subtle things that can go wrong (although the most important requirement is that padding always be unambiguous[13]), and there's no good reason to wing it.

[13] Because of this, it's impossible to avoid adding data to the end of the message, even when the message is block-aligned, at least if you want your padding scheme to work with arbitrary binary data.

The most widespread standard padding for block ciphers is called PKCS block padding. The goal of PKCS block padding is that the last byte of the padded plaintext should unambiguously describe how much padding was added to the message. PKCS padding sets every byte of padding to the number of bytes of padding added. If the input is block-aligned, an entire block of padding is added. For example, if four bytes of padding were needed, the proper padding would be:

0x04040404

If you're using a block cipher with 64-bit (8-byte) blocks, and the input is block-aligned, the padding would be:

0x0808080808080808

Here's an example API for adding and removing padding:

void spc_add_padding(unsigned char *pad_goes_here, int ptlen, int bl) {
   int i, n = (ptlen - 1) % bl + 1;
   
   for (i = 0;  i < n;  i++) *(pad_goes_here + i) = (unsigned char)n;
}
   
int spc_remove_padding(unsigned char *lastblock, int bl) {
  unsigned char i, n = lastblock[bl - 1];
  unsigned char *p = lastblock + bl;
   
   /* In your programs you should probably throw an exception or abort instead. */
  if (n > bl || n <= 0) return -1;
  for (i = n;  i;  i--) if (*--p != n) return -1;
  return bl - n; 
}

The spc_add_padding( ) function adds padding directly to a preallocated buffer called pad_goes_here. The function takes as input the length of the plaintext and the block length of the cipher. From that information, we figure out how many bytes to add, and we write the result into the appropriate buffer.

The spc_remove_padding( ) function deals with unencrypted plaintext. As input, we pass it the final block of plaintext, along with the block length of the cipher. The function looks at the last byte to see how many padding bytes should be present. If the final byte is bigger than the block length or is less than one, the padding is not in the right format, indicating a decryption error. Finally, we check to see whether the padded bytes are all in the correct format. If everything is in order, the function will return the number of valid bytes in the final block of data, which could be anything from zero to one less than the block length.

    [ Team LiB ] Previous Section Next Section