cybersecurity · intermediate · ~20 min

Validate PKCS#7 padding

Implement correct PKCS#7 padding validation — the check whose mistakes cause padding oracles.

Challenge

Block ciphers pad the final block with PKCS#7: if p bytes of padding are needed, every one of those bytes has the value p (1..block). Implement

int pkcs7_unpad(const unsigned char *buf, size_t n, size_t block)

returning the length without padding, or -1 if the padding is invalid. Valid input requires n > 0, n % block == 0, the last byte p in 1..block, and the last p bytes all equal p. (Sloppy validation here is the root of padding-oracle attacks.)

Starter code

#include <stddef.h>

int pkcs7_unpad(const unsigned char *buf, size_t n, size_t block) {
    /* TODO: validate n>0 and n%block==0; let p=last byte; require 1<=p<=block
       and the last p bytes all == p. Return n-p, or -1 if invalid. */
    (void)buf;(void)n;(void)block; return -1;
}

Common mistakes

Only checking the last byte (not all p bytes); allowing p=0 or p>block; not requiring a block multiple.

Edge cases to handle

Full block of padding (p==block -> length 0). p out of range. n not a multiple of block. Empty buffer.

Complexity

O(block).

Background lessons

Solve this exercise in the browser editor — compile and run against the test harness, no setup required.