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
- Verify the key and IV byte-for-byte against the values used at encryption time.
- 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.
- 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
- Treat invalid PKCS#5 padding as a strong signal of wrong key/IV/mode, not as a padding bug.
- Store the mode and padding alongside the ciphertext so decrypt uses the same parameters.
- Add an HMAC or length check over the ciphertext to detect corruption before decrypting.
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
- Invalid BIT padding.
- No padding requested but input is not a ${blockSize}-byte mu
- Unknown padding type: ${padding}
- Invalid ciphertext length: ${originalLength} bytes. Must be
- Unable to decrypt input with these parameters.
AI-assisted analysis of gchq/CyberChef@4290ea7539 (2026-08-13).
Data as JSON: /api/errors/b5404d07635e021a.
Report an issue: GitHub.