cybersecurity · intermediate · ~20 min

Validate PKCS#7 padding

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

Challenge

Validate and strip PKCS#7 padding correctly — sloppy validation here is the root cause of padding-oracle attacks.

Task

Implement int pkcs7_unpad(const unsigned char *buf, size_t n, size_t block) that returns the message length without padding, or -1 if the padding is invalid.

Input

  • buf, n: a fixture byte buffer (the padded data) and its length, provided by the grader.
  • block: the cipher block size. PKCS#7 pads with p bytes, each of value p, where p is in 1..block.

Output

Returns int: n - p (the unpadded length) when the padding is valid, else -1.

Example

{'A','B','C',0x01}, block 4   ->   3
{'A','B',0x02,0x02}, block 4   ->   2
{0x04,0x04,0x04,0x04}, block 4 ->   0
{'A','B','C',0x02}, block 4    ->   -1   (last 2 bytes not both 0x02)

Edge cases

  • Valid input requires n > 0, n % block == 0, the last byte p in 1..block, and the last p bytes all equal p.
  • A full block of padding (every byte equals block) is valid and returns 0.
  • p == 0, p > block, or n not a block multiple is invalid.

Rules

  • Check every one of the last p bytes, not just the last one — that is the difference between safe and oracle-leaking validation.

Input format

A fixture byte buffer buf, its length n, and the block size block.

Output format

An int: the unpadded length n - p, or -1 if the padding is invalid.

Constraints

Require n>0, n % block == 0, last byte p in 1..block, and all last p bytes == p.

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.