gchq/CyberChef · error · OperationError
With ECB or CBC modes, the input must be divisible into 16 b
Error message
With ECB or CBC modes, the input must be divisible into 16 byte blocks. (${cipherText.length & 0xF} bytes extra) What it means
decryptSM4 at SM4.mjs:259 enforces block alignment for ECB/CBC unless ignorePadding is set. SM4's block size is 16 bytes; a ciphertext whose length is not a multiple of 16 cannot be the output of a correct ECB/CBC encrypt and is rejected.
Source
Thrown at src/core/lib/SM4.mjs:259
*
* @param {byteArray} cipherText - The ciphertext
* @param {byteArray} key - The cipher key, 16 bytes.
* @param {byteArray} iv - The IV or nonce, 16 bytes (not used with ECB mode)
* @param {string} mode - The block cipher mode "CBC", "ECB", "CFB", "OFB", "CTR"
* @param {boolean] ignorePadding - If true, ignore padding issues in ECB/CBC mode.
* @returns {byteArray} - The cipher text.
*/
export function decryptSM4(cipherText, key, iv, mode="ECB", ignorePadding=false) {
const originalLength = cipherText.length;
if (originalLength === 0)
return [];
let roundKey = initSM4RoundKey(bytesToInts(key, 0));
if (mode === "ECB" || mode === "CBC") {
/* Init decryption key */
roundKey = roundKey.reverse();
if ((originalLength & 0xF) !== 0 && !ignorePadding)
throw new OperationError(`With ECB or CBC modes, the input must be divisible into 16 byte blocks. (${cipherText.length & 0xF} bytes extra)`);
} else { /* Pad dummy bytes for other modes, chop them off at the end */
while ((cipherText.length & 0xF) !== 0)
cipherText.push(0);
}
const clearText = [];
switch (mode) {
case "ECB":
for (let i = 0; i < cipherText.length; i += BLOCKSIZE)
Array.prototype.push.apply(clearText, intsToBytes(encryptBlockSM4(bytesToInts(cipherText, i), roundKey)));
break;
case "CBC":
iv = bytesToInts(iv, 0);
for (let i = 0; i < cipherText.length; i += BLOCKSIZE) {
const block = encryptBlockSM4(bytesToInts(cipherText, i), roundKey);
block[0] ^= iv[0]; block[1] ^= iv[1];
block[2] ^= iv[2]; block[3] ^= iv[3];
Array.prototype.push.apply(clearText, intsToBytes(block));View on GitHub (pinned to 4290ea7539)
Solutions
- Verify the ciphertext byte length is a multiple of 16 before calling decryptSM4.
- Re-derive the byte array from its hex/base64 encoding and check for truncation.
- Confirm the decrypt mode matches the encrypt mode.
- If you knowingly want to skip alignment/padding checks, pass ignorePadding=true (but the result will be unreliable for mis-sized input).
Example fix
// before
const pt = decryptSM4(ct, key, iv, "CBC"); // ct.length === 17
// after
if (ct.length & 0xF) throw new Error(`ciphertext not block-aligned: ${ct.length} bytes`);
const pt = decryptSM4(ct, key, iv, "CBC"); Defensive patterns
Strategy: validation
Validate before calling
function assertSm4CipherAligned(cipherText, ignorePadding, mode) {
if (!ignorePadding && (mode === "ECB" || mode === "CBC")) {
if (cipherText.length & 0xF)
throw new TypeError(
`ECB/CBC ciphertext must be a 16-byte multiple; got ${cipherText.length} bytes`);
}
} Type guard
function isSm4CipherBlockAligned(bytes) {
return Number.isInteger(bytes.length) && (bytes.length & 0xF) === 0;
} Try / catch
import OperationError from "../errors/OperationError.mjs";
try {
assertSm4CipherAligned(ct, ignorePadding, mode);
const pt = decryptSM4(ct, key, iv, mode, ignorePadding);
} catch (e) {
if (e instanceof OperationError && /divisible into 16 byte blocks/.test(e.message)) {
// re-derive ct from hex/base64 and check for truncation
} else throw e;
} Prevention
- Validate ciphertext length is a multiple of 16 before decrypting ECB/CBC.
- Decode hex/base64 through a single tested helper.
- Ensure decrypt mode matches encrypt mode.
When it happens
Trigger: decryptSM4(cipherText, key, iv, mode='ECB'|'CBC', ignorePadding=false) with (cipherText.length & 0xF) !== 0. Caused by truncated/corrupted ciphertext, encoding/decoding error in the hex/base64 path, or feeding a stream-mode ciphertext to an ECB/CBC decryptor.
Common situations: Hex string of odd length producing a short byte array; base64 padding lost in transit; mode mismatch where CFB/CTR output is decrypted as ECB/CBC; manual copy of ciphertext dropping a byte.
Related errors
- Invalid ciphertext length: ${originalLength} bytes. Must be
- No padding requested in ${mode} mode but input is not a 16-b
- Invalid block cipher mode: ${mode}
- Invalid PKCS#7 padding.
- No padding requested but input length (${message.length} byt
AI-assisted analysis of gchq/CyberChef@4290ea7539 (2026-08-13).
Data as JSON: /api/errors/f3410798741e9a75.
Report an issue: GitHub.