gchq/CyberChef · error · OperationError

Invalid PKCS#5 padding.

Error message

Invalid PKCS#5 padding.

What it means

Thrown by RC6.removePadding for PKCS5 when the trailing pad byte count is in range (1..blockSize) but at least one of the final N bytes does not equal N. PKCS#5 padding requires the last N bytes all to equal N; a mismatch means the ciphertext was wrong, the padding type was wrong, or the data is not PKCS5-padded.

Source

Thrown at src/core/lib/RC6.mjs:415

 * @returns {number[]} - Unpadded message
 */
function removePadding(message, padding, blockSize) {
    if (message.length === 0) return message;

    switch (padding) {
        case "NO":
        case "ZERO":
        case "RANDOM":
            // These padding types cannot be reliably removed
            return message;

        case "PKCS5": {
            const padByte = message[message.length - 1];
            if (padByte > 0 && padByte <= blockSize) {
                // Verify padding
                for (let i = 0; i < padByte; i++) {
                    if (message[message.length - 1 - i] !== padByte) {
                        throw new OperationError("Invalid PKCS#5 padding.");
                    }
                }
                return message.slice(0, message.length - padByte);
            }
            throw new OperationError("Invalid PKCS#5 padding.");
        }

        case "BIT": {
            // Find 0x80 byte working backwards, skipping zeros
            for (let i = message.length - 1; i >= 0; i--) {
                if (message[i] === 0x80) {
                    return message.slice(0, i);
                } else if (message[i] !== 0) {
                    throw new OperationError("Invalid BIT padding.");
                }
            }
            throw new OperationError("Invalid BIT padding.");
        }

View on GitHub (pinned to 4290ea7539)

Solutions

  1. Verify the key and IV match those used for encryption.
  2. Confirm the data was actually PKCS5-padded at encryption time.
  3. If unsure of padding, decrypt with 'NO' and inspect the tail bytes.

Example fix

// before: decrypt with PKCS5 though sender used BIT
// after: match the sender's padding scheme
const pt = decryptRC6(ct, key, iv, 'CBC', 'BIT');
Defensive patterns

Strategy: try-catch

Validate before calling

function isValidPkcs5Tail(message, blockSize) {
  const n = message[message.length - 1];
  if (n < 1 || n > blockSize) return false;
  for (let i = 0; i < n; i++) if (message[message.length - 1 - i] !== n) return false;
  return true;
}

Type guard

function hasValidPkcs5Padding(message, blockSize) {
  const n = message[message.length - 1];
  return n >= 1 && n <= blockSize && message.slice(-n).every(b => b === n);
}

Try / catch

try {
  return decryptRC6(ct, key, iv, mode, 'PKCS5', rounds, w);
} catch (e) {
  if (e instanceof OperationError && /Invalid PKCS#5 padding/.test(e.message)) {
    // verify key/IV, or decrypt with 'NO' to inspect the tail bytes
    return decryptRC6(ct, key, iv, mode, 'NO', rounds, w);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling decryptRC6(...) with padding 'PKCS5' on ciphertext whose decrypted final block does not end in valid PKCS#5 bytes — wrong key, wrong IV, double-decryption, or the data was padded differently.

Common situations: Wrong key/IV producing random-looking plaintext; data was padded with ZERO/BIT but decrypted as PKCS5; ciphertext truncated/extended by a byte; CBC chain broken.

Related errors


AI-assisted analysis of gchq/CyberChef@4290ea7539 (2026-08-13). Data as JSON: /api/errors/cc2b3fc4ebf2212e. Report an issue: GitHub.