gchq/CyberChef · error · OperationError

No padding requested in ${mode} mode but input is not a 16-b

Error message

No padding requested in ${mode} mode but input is not a 16-byte multiple.

What it means

encryptSM4 at SM4.mjs:174 guards the noPadding path. In ECB/CBC the input must already be a whole number of 16-byte blocks because the cipher cannot stream or truncate; with noPadding=true and any remainder, encryption is refused rather than silently mis-padding.

Source

Thrown at src/core/lib/SM4.mjs:174

 * @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} noPadding - Don't add PKCS#7 padding if set.
 * @returns {byteArray} - The cipher text.
 */
export function encryptSM4(message, key, iv, mode="ECB", noPadding=false) {
    const messageLength = message.length;
    if (messageLength === 0)
        return [];
    const roundKey = initSM4RoundKey(bytesToInts(key, 0));

    /* Pad with PKCS#7 if requested for ECB/CBC else add zeroes (which are sliced off at the end) */
    let padByte = 0;
    let nPadding = 16 - (message.length & 0xF);
    if (mode === "ECB" || mode === "CBC") {
        if (noPadding) {
            if (nPadding !== 16)
                throw new OperationError(`No padding requested in ${mode} mode but input is not a 16-byte multiple.`);
            nPadding = 0;
        } else
            padByte = nPadding;
    }
    for (let i = 0; i < nPadding; i++)
        message.push(padByte);

    const cipherText = [];
    switch (mode) {
        case "ECB":
            for (let i = 0; i < message.length; i += BLOCKSIZE)
                Array.prototype.push.apply(cipherText, intsToBytes(encryptBlockSM4(bytesToInts(message, i), roundKey)));
            break;
        case "CBC":
            iv = bytesToInts(iv, 0);
            for (let i = 0; i < message.length; i += BLOCKSIZE) {
                const block = bytesToInts(message, i);
                block[0] ^= iv[0]; block[1] ^= iv[1];

View on GitHub (pinned to 4290ea7539)

Solutions

  1. Pre-pad the message to a 16-byte multiple yourself (e.g. with explicit zero bytes) before calling encryptSM4 with noPadding=true.
  2. Or set noPadding=false to let the library apply PKCS#7 automatically.
  3. Validate message.length % 16 === 0 up front so the failure is reported at the trust boundary, not deep in the cipher.

Example fix

// before
const ct = encryptSM4(msg, key, iv, "CBC", true); // msg is 17 bytes
// after: align to block boundary explicitly
const aligned = msg.concat(new Array((16 - msg.length % 16) % 16).fill(0));
const ct = encryptSM4(aligned, key, iv, "CBC", true);
Defensive patterns

Strategy: validation

Validate before calling

function assertSm4NoPaddingAligned(message, noPadding, mode) {
  if (noPadding && (mode === "ECB" || mode === "CBC")) {
    if (message.length & 0xF)
      throw new TypeError(
        `noPadding requires a 16-byte multiple; got ${message.length} bytes`);
  }
}

Type guard

function isSm4BlockAligned(bytes) {
  return Number.isInteger(bytes.length) && (bytes.length & 0xF) === 0;
}

Try / catch

import OperationError from "../errors/OperationError.mjs";
try {
  assertSm4NoPaddingAligned(msg, noPadding, mode);
  const ct = encryptSM4(msg, key, iv, mode, noPadding);
} catch (e) {
  if (e instanceof OperationError && /No padding requested/.test(e.message)) {
    // either pre-pad the message or enable PKCS#7
  } else throw e;
}

Prevention

When it happens

Trigger: encryptSM4(message, key, iv, mode='ECB'|'CBC', noPadding=true) where message.length % 16 != 0. Typical cause: caller deliberately disabled PKCS#7 padding but supplied a message that is not block-aligned.

Common situations: Protocol that requires no padding on the wire but the framing layer did not pre-pad to 16 bytes; toggling noPadding to avoid PKCS#7 overhead without aligning the payload; batch processing of variable-length records fed straight into ECB.

Related errors


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