embassy-rs/embassy · error

Output buffer length must match input length.

Error message

Output buffer length must match input length.

What it means

The CRYP payload call requires the output buffer to be at least as long as the input; hardware writes one block per input block, so a shorter output would be overrun. It panics when input.len() > output.len().

Solutions

  1. Size the output buffer to be at least input.len() (same length for streaming modes).
  2. For padded block modes, allocate output covering the padded length as the driver requires.
  3. If the destination is smaller, process the input in chunks that fit it.

Example fix

// before
let mut out = [0u8; 8];
ctx.payload(&ciphertext16, &mut out, true); // panics
// after
let mut out = [0u8; 16];
ctx.payload(&ciphertext16, &mut out, true);
Defensive patterns

Strategy: validation

Validate before calling

assert!(output.len() >= input.len(), "output buffer too small for CRYP payload");

Prevention

When it happens

Trigger: Calling payload()/encrypt/decrypt with an output slice shorter than the input — e.g. decrypting 16 bytes of ciphertext into an 8-byte buffer, or a mis-sized scratch buffer.

Common situations: Hardcoded buffer sizes not matching input length; in-place buffers reused with wrong slice bounds; porting from APIs that return an owned buffer to this caller-buffer API.

Related errors


AI-assisted analysis of embassy-rs/embassy@463a07b963 (2026-09-10). Data as JSON: /api/errors/16f677dafba0cffc. Report an issue: GitHub.

Appendix: source

Thrown at embassy-stm32/src/cryp/mod.rs:1419

        // Perform checks for correctness.
        if !ctx.aad_complete && ctx.header_len > 0 {
            panic!("Additional associated data must be processed first!");
        } else if !ctx.aad_complete {
            #[cfg(any(cryp_v2, cryp_v3, cryp_v4))]
            {
                ctx.aad_complete = true;
                T::regs().cr().modify(|w| w.set_crypen(false));
                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;
        }

View on GitHub (pinned to 463a07b963)