embassy-rs/embassy · error
Input must be a multiple of
Error message
Input must be a multiple of {} bytes in ECB and CBC modes. Consider padding or ciphertext stealing. What it means
For ECB and CBC the CRYP hardware applies no automatic padding, so the entire input — including the final block — must be an exact multiple of the AES block size. The driver panics with the block size in the {} slot, suggesting software padding or ciphertext stealing.
Solutions
- Apply PKCS#7 (or other) padding in software before the final ECB/CBC block; strip it after decrypt.
- Implement ciphertext stealing (CBC-CTS) for the tail blocks, as the message suggests.
- Switch to CTR or GCM, which handle arbitrary lengths natively.
Example fix
// before
let pt = *b"hello world"; // 11 bytes
ctx.payload(&pt, &mut out, true); // ECB/CBC panics
// after
let mut pt = *b"hello world\u{5}\u{5}\u{5}\u{5}\u{5}"; // PKCS#7 pad to 16
ctx.payload(&pt, &mut out, true); Defensive patterns
Strategy: validation
Validate before calling
if input.len() % 16 != 0 { /* apply PKCS#7 padding or use CTR/GCM instead */ } Prevention
- Remember hardware ECB/CBC applies no padding
- Centralize pad/unpad helpers for ECB/CBC use
- Prefer CTR/GCM when plaintext lengths are arbitrary
When it happens
Trigger: Calling encrypt/decrypt in ECB or CBC mode with input length not divisible by 16 bytes (e.g. 30-byte plaintext with last_block=true).
Common situations: Encrypting raw records whose lengths aren't block-aligned; switching from a software AES-CBC that pads to this hardware driver; padding handled at an unexpected layer.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- Invalid key size
- Additional associated data must be processed first!
- Cannot update AAD after starting payload!
- Input length must be a multiple of
- Message is too large for given IV size.
AI-assisted analysis of embassy-rs/embassy@463a07b963 (2026-09-10).
Data as JSON: /api/errors/1dd9453627e3b167.
Report an issue: GitHub.
Appendix: source
Thrown at embassy-stm32/src/cryp/mod.rs:1428
T::regs().cr().modify(|w| w.set_gcm_ccmph(2));
T::regs().cr().modify(|w| w.set_fflush(true));
T::regs().cr().modify(|w| w.set_crypen(true));
}
}
if ctx.last_block_processed {
panic!("The last block has already been processed!");
}
if input.len() > output.len() {
panic!("Output buffer length must match input length.");
}
if !last_block {
if last_block_remainder != 0 {
panic!("Input length must be a multiple of {} bytes.", C::BLOCK_SIZE);
}
}
if C::REQUIRES_PADDING {
if last_block_remainder != 0 {
panic!(
"Input must be a multiple of {} bytes in ECB and CBC modes. Consider padding or ciphertext stealing.",
C::BLOCK_SIZE
);
}
}
if last_block {
ctx.last_block_processed = true;
}
// Load data into core, block by block.
let num_full_blocks = input.len() / C::BLOCK_SIZE;
for block in 0..num_full_blocks {
let index = block * C::BLOCK_SIZE;
// Write block in
self.write_bytes_blocking(C::BLOCK_SIZE, &input[index..index + C::BLOCK_SIZE]);
// Read block out
self.read_bytes_blocking(C::BLOCK_SIZE, &mut output[index..index + C::BLOCK_SIZE]);
}View on GitHub (pinned to 463a07b963)