{"record":{"id":"50605980a3760ddf","repo":"embassy-rs/embassy","slug":"input-length-must-be-a-multiple-of-bytes","errorCode":null,"errorMessage":"Input length must be a multiple of {} bytes.","messagePattern":"Input length must be a multiple of (.+?) bytes\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"embassy-stm32/src/cryp/mod.rs","lineNumber":1423,"sourceCode":"        } else if !ctx.aad_complete {\n            #[cfg(any(cryp_v2, cryp_v3, cryp_v4))]\n            {\n                ctx.aad_complete = true;\n                T::regs().cr().modify(|w| w.set_crypen(false));\n                T::regs().cr().modify(|w| w.set_gcm_ccmph(2));\n                T::regs().cr().modify(|w| w.set_fflush(true));\n                T::regs().cr().modify(|w| w.set_crypen(true));\n            }\n        }\n        if ctx.last_block_processed {\n            panic!(\"The last block has already been processed!\");\n        }\n        if input.len() > output.len() {\n            panic!(\"Output buffer length must match input length.\");\n        }\n        if !last_block {\n            if last_block_remainder != 0 {\n                panic!(\"Input length must be a multiple of {} bytes.\", C::BLOCK_SIZE);\n            }\n        }\n        if C::REQUIRES_PADDING {\n            if last_block_remainder != 0 {\n                panic!(\n                    \"Input must be a multiple of {} bytes in ECB and CBC modes. Consider padding or ciphertext stealing.\",\n                    C::BLOCK_SIZE\n                );\n            }\n        }\n        if last_block {\n            ctx.last_block_processed = true;\n        }\n\n        // Load data into core, block by block.\n        let num_full_blocks = input.len() / C::BLOCK_SIZE;\n        for block in 0..num_full_blocks {\n            let index = block * C::BLOCK_SIZE;","sourceCodeStart":1405,"sourceCodeEnd":1441,"githubUrl":"https://github.com/embassy-rs/embassy/blob/463a07b963419a1bfe61d5d597c44acb810afb8b/embassy-stm32/src/cryp/mod.rs#L1405-L1441","documentation":"For non-final processing the driver requires input length to be a multiple of the cipher block size (16 bytes for AES), since hardware without padding cannot consume a partial block. A non-final chunk with a remainder panics, reporting the required block size via the {} format argument.","triggerScenarios":"Calling payload() with last_block=false and input.len() % C::BLOCK_SIZE != 0 — e.g. a 10-byte chunk into AES.","commonSituations":"Reading files in arbitrary-size chunks and passing them straight to the cipher; protocol framing yielding non-aligned bodies; forgetting only the final block may be partial.","solutions":["Buffer input into block-aligned (16-byte) chunks; only the final chunk with last_block=true may be shorter where the mode allows.","Use a padding/CTS mode for arbitrary-length inputs, applying padding before the final call.","Pad the input yourself to a block multiple and track the real length for verification."],"exampleFix":"// before\nfor chunk in data.chunks(1024 + 7) { ctx.payload(chunk, &mut out, false); } // unaligned\n// after\nfor chunk in data.chunks(1024) { ctx.payload(chunk, &mut out, false); } // block-aligned","handlingStrategy":"validation","validationCode":"if !is_last && input.len() % 16 != 0 { /* stage bytes until a full 16-byte block is available */ }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use block-multiple read sizes in streaming code","Keep a small staging buffer to align partial chunks","Document block alignment requirements per mode"],"tags":["embedded","crypto","cryp","block-size","panic"],"backgroundTag":"invalid-argument-format","analyzedSha":"463a07b963419a1bfe61d5d597c44acb810afb8b","analyzedAt":"2026-09-10T13:38:26.660Z","contentChangedAt":"2026-09-10T13:38:26.660Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}