gchq/CyberChef · error · OperationError

Invalid PKCS#5 padding.

Error message

Invalid PKCS#5 padding.

What it means

Thrown by removePadding() in Twofish.mjs during PKCS#5 unpadding when at least one of the trailing pad bytes does not equal the declared pad value. PKCS#5 padding requires the last N bytes to all equal N; a mismatch means the ciphertext was altered, decrypted with the wrong key/IV, or was not PKCS#5-padded to begin with. This is the inner verification loop failing.

Source

Thrown at src/core/lib/Twofish.mjs:410

 * @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 byte-for-byte against the values used at encryption time.
  2. Confirm the encrypt side used PKCS5 padding and the same mode (ECB/CBC); if it used no padding or a stream mode, change the decrypt call accordingly.
  3. If interoperating with PKCS#7 from another library, note that is compatible — the issue is data integrity, not the padding name.

Example fix

// before: decrypting with wrong IV produces invalid padding
decryptTwofish(ct, key, wrongIv, "CBC", "PKCS5"); // throws
// after
decryptTwofish(ct, key, correctIv, "CBC", "PKCS5");
Defensive patterns

Strategy: try-catch

Validate before calling

function isValidPkcs5Tail(bytes, blockSize = 16) {
    if (bytes.length === 0) return false;
    const n = bytes[bytes.length - 1];
    if (n < 1 || n > blockSize || n > bytes.length) return false;
    for (let i = 0; i < n; i++) {
        if (bytes[bytes.length - 1 - i] !== n) return false;
    }
    return true;
}
// decrypt without padding, inspect, then strip manually if valid
const probe = decryptTwofish(ct, key, iv, mode, "NO");
if (!isValidPkcs5Tail(probe)) {
    throw new Error("Decrypted output has invalid PKCS#5 padding — check key/IV/mode.");
}

Type guard

function isValidPkcs5Tail(bytes, blockSize = 16) {
    if (!bytes || bytes.length === 0) return false;
    const n = bytes[bytes.length - 1];
    if (n < 1 || n > blockSize || n > bytes.length) return false;
    return bytes.slice(bytes.length - n).every(b => b === n);
}

Try / catch

try {
    pt = decryptTwofish(ct, key, iv, "CBC", "PKCS5");
} catch (e) {
    if (e instanceof OperationError && /Invalid PKCS#5 padding/.test(e.message)) {
        // almost always key/IV/mode mismatch; do NOT strip bytes blindly
        return { error: "Wrong key/IV/mode — decryption produced invalid padding." };
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling decryptTwofish() in ECB/CBC with padding "PKCS5" where the decrypted final block's tail bytes are inconsistent. Causes: wrong key, wrong IV, truncated/swapped ciphertext blocks, mode mismatch (decrypting CTR ciphertext as CBC), or the data was never PKCS#5-padded (it used ZERO/RANDOM/NO padding but declared PKCS5).

Common situations: Key/IV mismatch between encrypt and decrypt; bit flip in transit or storage; decrypting data encrypted by another tool that used a different padding; off-by-one block slicing.

Related errors


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