gchq/CyberChef · error · OperationError
Invalid PKCS#7 padding.
Error message
Invalid PKCS#7 padding.
What it means
decryptSM4's PKCS#7 check at SM4.mjs:323. After decrypting an ECB/CBC buffer it reads the trailing byte as the pad length; if that value exceeds 16 (the SM4 block size) it cannot be a valid PKCS#7 pad and is rejected. This almost always means the plaintext is garbage — wrong key, wrong IV, or wrong mode.
Source
Thrown at src/core/lib/SM4.mjs:323
let iv2 = [...iv]; /* containing the IV + counter */
iv2[3] += (i >> 4);/* Using a 32 bit counter here. 64 Gb encrypts should be enough for everyone. */
iv2 = encryptBlockSM4(iv2, roundKey);
const block = bytesToInts(cipherText, i);
block[0] ^= iv2[0]; block[1] ^= iv2[1];
block[2] ^= iv2[2]; block[3] ^= iv2[3];
Array.prototype.push.apply(clearText, intsToBytes(block));
}
break;
default:
throw new OperationError(`Invalid block cipher mode: ${mode}`);
}
/* Check PKCS#7 padding */
if (mode === "ECB" || mode === "CBC") {
if (ignorePadding)
return clearText;
const padByte = clearText[clearText.length - 1];
if (padByte > 16)
throw new OperationError("Invalid PKCS#7 padding.");
for (let i = 0; i < padByte; i++)
if (clearText[clearText.length -i - 1] !== padByte)
throw new OperationError("Invalid PKCS#7 padding.");
return clearText.slice(0, clearText.length - padByte);
}
return clearText.slice(0, originalLength);
}
View on GitHub (pinned to 4290ea7539)
Solutions
- Confirm the key and IV are identical to those used for encryption.
- Verify the encrypt mode matches the decrypt mode.
- If the data was encrypted without PKCS#7 padding, decrypt with ignorePadding=true.
- As a diagnostic, decrypt with ignorePadding=true and inspect the raw plaintext to see if it looks correct.
Example fix
// before const pt = decryptSM4(ct, wrongKey, iv, "CBC"); // after const pt = decryptSM4(ct, correctKey, iv, "CBC");
Defensive patterns
Strategy: validation
Validate before calling
// After a trial decrypt with ignorePadding=true, sanity-check the trailing byte.
function looksLikeValidPkcs7Pad(plain, blockSize = 16) {
if (plain.length === 0) return false;
const padByte = plain[plain.length - 1];
if (padByte < 1 || padByte > blockSize) return false;
for (let i = 0; i < padByte; i++)
if (plain[plain.length - 1 - i] !== padByte) return false;
return true;
} Type guard
function hasPlausiblePkcs7TrailingByte(plain, blockSize = 16) {
return plain.length > 0 && plain[plain.length - 1] >= 1 && plain[plain.length - 1] <= blockSize;
} Try / catch
import OperationError from "../errors/OperationError.mjs";
try {
const pt = decryptSM4(ct, key, iv, "CBC");
} catch (e) {
if (e instanceof OperationError && /Invalid PKCS#7 padding/.test(e.message)) {
// retry with ignorePadding=true to inspect raw plaintext; treat as wrong-key/mode signal
} else throw e;
} Prevention
- Keep key, IV, and mode identical between encrypt and decrypt.
- If encrypt did not use PKCS#7, decrypt with ignorePadding=true and strip padding yourself.
- Treat a padding error as an integrity signal — do not return partial plaintext.
When it happens
Trigger: decryptSM4(cipherText, key, iv, mode='ECB'|'CBC', ignorePadding=false) where the last decrypted byte is greater than 16. Typical cause: decrypting with the wrong key/IV produces random plaintext whose final byte happens to be > 16.
Common situations: Key/IV mismatch between encrypt and decrypt; mode mismatch (encrypt was CTR but decrypt is CBC); ciphertext from a different cipher entirely; encrypt side did not apply PKCS#7 (e.g. used noPadding) but decrypt expects it.
Related errors
- No padding requested in ${mode} mode but input is not a 16-b
- With ECB or CBC modes, the input must be divisible into 16 b
- Invalid PKCS#5 padding.
- Invalid BIT padding.
- Invalid PKCS#5 padding.
AI-assisted analysis of gchq/CyberChef@4290ea7539 (2026-08-13).
Data as JSON: /api/errors/2949abdec1e34700.
Report an issue: GitHub.