Padding

Updated: April 19, 2023

Some cryptographic primitives, such as AES ciphers in block cipher modes of operation, often require that the input data size be a multiple of the primitive's block size. Because the size of some data (e.g., plaintext) can be variable, padding can be added to meet the primitive's size requirements.

Padding also defends against plaintext length attacks by hiding the length of the plaintext.

Padding is only required when an algorithm uses a block cipher mode of operation and its input is not a multiple of the cipher block size. Padding is optional if the input size is already a multiple of the block size.

The qcrypto cipher algorithm APIs can provide automatic padding; otherwise, the caller has to provide any padding the algorithm requires.

The supported padding algorithms described here are ones that are reversible, which means that there is no ambiguity when the ciphertext is decrypted and unpadded into the plaintext. If there is an error in the padding removal, the plaintext is corrupted and shouldn't be trusted.

Note:

Both PKCS7 and ISO7816 padding add an extra block to the input data even if the input data is a multiple of the block size.

The cryptography industry is moving away from block ciphers and padding towards stream ciphers, which work on input of any length and don't require padding.

PKCS7 padding

The PKCS7 padding mode adds whole bytes to the end of input data until it is equal to a multiple of the blocksize. The padding byte value is the number of bytes that need to be added to reach the blocksize multiple.

PKCS7 padding supports blocksizes of up to 255 bytes.

See the library reference for detailed descriptions of the following functions:

ISO7816 padding

The ISO.2FIEC_7816-4 padding mode adds a byte of value 0x80 followed by as many 0x00 bytes as are required to make the data equal to a multiple of the blocksize.

See the library reference for detailed descriptions of the following functions:

Padding examples

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <qcrypto/qcrypto.h>
#include <qcrypto/qcrypto_error.h>
#include <private/qcrypto/qcrypto_internal.h>

int main(void)
{
    int ret;
    int pad_result = 1;
    int unpad_result = 1;
    size_t blocksize = 16;

    const char in_hex[] = "abab";
    const size_t insize = (sizeof(in_hex)-1)/2;
    uint8_t inbuf[insize];
    uint8_t *in_bin = inbuf;
    size_t insize_cmp = 0;
    char in_cmp_hexbuf[insize*2];
    char *in_cmp_hex = in_cmp_hexbuf;

    const char out_hex[] = "abab0e0e0e0e0e0e0e0e0e0e0e0e0e0e";
    const size_t outsize = (sizeof(out_hex)-1)/2;
    size_t outsize_cmp = outsize;
    uint8_t out_cmpbuf[outsize];
    uint8_t *out_cmp = out_cmpbuf;
    char out_cmp_hexbuf[outsize*2];
    char *out_cmp_hex = out_cmp_hexbuf;

    /* Initialize the Qcrypto Library */
    ret = qcrypto_init(QCRYPTO_INIT_LAZY, NULL);
    if (ret != QCRYPTO_R_EOK) {
        fprintf(stderr, "qcryto_init() failed (%d:%s)\n", ret, qcrypto_strerror(ret));
        goto done;
    }

    /* Convert Input */
    ret = qcrypto_hex2bin(in_bin, in_hex, insize);
    if (ret != QCRYPTO_R_EOK) {
        fprintf(stderr, "qcrypto_hex2bin() failed (%d:%s)\n", ret, qcrypto_strerror(ret));
        goto done;
    }

    /* Padding pkcs7 pad */
    ret = qcrypto_padding_pkcs7_pad(in_bin, insize, out_cmp, &outsize_cmp, blocksize);
    if (ret != QCRYPTO_R_EOK) {
        fprintf(stderr, "qcrypto_padding_pkcs7_pad() failed (%d:%s)\n", ret, qcrypto_strerror(ret));
        goto done;
    }

    /* Compare pad length */
    if (outsize_cmp != outsize) {
        fprintf(stderr, "Computed pad length failed to match with expected pad length\n");
        goto done;
    }

    /* Convert pad result */
    qcrypto_bin2hex(out_cmp_hex, out_cmp, outsize);

    /* Compare pad results */
    pad_result = memcmp(out_cmp_hex, out_hex, outsize);
    if (pad_result == 0) {
         printf("Computed pad matches with expected pad\n");
    } else {
         fprintf(stderr, "Computed pad failed to match with expected pad\n");
         goto done;
    }

    /* Padding pkcs7 unpad */
    insize_cmp = outsize;
    ret = qcrypto_padding_pkcs7_unpad(out_cmp, &insize_cmp);
    if (ret != QCRYPTO_R_EOK) {
        fprintf(stderr, "qcrypto_padding_pkcs7_unpad() failed (%d:%s)\n", ret, qcrypto_strerror(ret));
        goto done;
    }

   /* Compare unpad length */
    if (insize_cmp != insize) {
        fprintf(stderr, "Computed unpad length failed to match with expected unpad length\n");
        goto done;
    }

    /* Convert unpad result */
    qcrypto_bin2hex(in_cmp_hex, out_cmp, insize_cmp);

    /* Compare unpad results */
    unpad_result = memcmp(in_cmp_hex, in_hex, insize_cmp);
    if (unpad_result == 0) {
         printf("Computed unpad matches with expected unpad\n");
    } else {
         fprintf(stderr, "Computed unpad failed to match with expected unpad\n");
         goto done;
    }
    goto done;

done:
    /* Uninitialize the Qcrypto Library */
    qcrypto_uninit();

    return ret;
}

#if defined(__QNXNTO__) && defined(__USESRCVERSION)
#include <sys/srcversion.h>
__SRCVERSION("$URL$ $Rev$")
#endif