gchq/CyberChef · error · OperationError

Invalid PKCS#5 padding.

Error message

Invalid PKCS#5 padding.

What it means

During PRESENT decryption with PKCS5 padding, removePadding reads the last byte as padByte and verifies that the final padByte bytes all equal padByte (PKCS#5/PKCS#7 spec). If any of those bytes differs, the padding is invalid and decryption is rejected. This branch fires when padByte is itself in range but one of the preceding bytes disagrees - the classic symptom of a wrong key.

Source

Thrown at src/core/lib/Present.mjs:295

 * @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 matches the one used for encryption (same length - 10 or 16 bytes - and same bytes).
  2. Confirm the IV is correct and in the right byte order for CBC mode.
  3. Check that the encrypting party actually used PKCS5 padding; if not, set the matching padding type on decrypt.
  4. Inspect the last block of decrypted bytes - if it looks random, the key is almost certainly wrong.
  5. If you cannot guarantee PKCS5, decrypt with padding='NO' and inspect the raw tail bytes.

Example fix

// before
const pt = decryptPRESENT(ct, wrongKey, iv, 'CBC', 'PKCS5'); // -> Invalid PKCS#5 padding

// after - debug by skipping padding validation
const raw = decryptPRESENT(ct, wrongKey, iv, 'CBC', 'NO');
console.log(raw.slice(-8)); // inspect last block to confirm wrong-key hypothesis
// then supply the correct key:
const pt = decryptPRESENT(ct, correctKey, iv, 'CBC', 'PKCS5');
Defensive patterns

Strategy: try-catch

Validate before calling

function isValidPKCS5(bytes, blockSize = 8) {
  const pad = bytes[bytes.length - 1];
  if (!(pad > 0 && pad <= blockSize)) return false;
  for (let i = 0; i < pad; i++) {
    if (bytes[bytes.length - 1 - i] !== pad) return false;
  }
  return true;
}

const raw = decryptPRESENT(ct, key, iv, mode, 'NO');
if (!isValidPKCS5(raw)) throw new Error('Wrong key or non-PKCS5 source data');

Try / catch

try {
  return decryptPRESENT(ct, key, iv, mode, 'PKCS5');
} catch (e) {
  if (!/PKCS#5/.test(e.message)) throw e;
  // likely wrong key - inspect raw then surface a clear error
  const raw = decryptPRESENT(ct, key, iv, mode, 'NO');
  throw new Error('Decryption produced invalid PKCS5 padding; key is probably wrong.');
}

Prevention

When it happens

Trigger: Calling decryptPRESENT(cipherText, wrongKey, iv, mode, 'PKCS5') - the decrypted plaintext looks random and the tail bytes do not form valid PKCS5 padding. Also fires with the right key but corrupted ciphertext bytes near the end of the last block.

Common situations: Wrong key supplied (most common); wrong IV in CBC mode corrupting the first block but randomly fixing the last; ciphertext truncated or with a byte flipped; message was not PKCS5-padded on the encrypting side (used ZERO/RANDOM instead).

Related errors


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