embassy-rs/embassy · error

Digest buffer must be at least

Error message

Digest buffer must be at least {} bytes long.

What it means

The blocking HASH peripheral driver panics in finish_blocking when the caller-supplied digest output slice is shorter than the algorithm's digest length (DIGEST_WORDS * 4 bytes, e.g. 32 bytes for SHA-256). The library cannot partially write a digest, so it fails fast instead of silently truncating.

Solutions

  1. Size the digest buffer to at least A::DIGEST_WORDS * 4 bytes for the algorithm in use (e.g. [u8; 32] for SHA-256, [u8; 64] for SHA-512)
  2. Before the call, check digest.len() >= expected digest length and return a Result error instead of panicking
  3. Derive the buffer size from the algorithm's associated constants rather than hardcoding

Example fix

// before
let mut digest = [0u8; 20];
hasher.finish_blocking(&mut digest); // panics for SHA-256
// after
let mut digest = [0u8; <MyHash as DigestAlgorithm>::DIGEST_WORDS * 4];
hasher.finish_blocking(&mut digest);
Defensive patterns

Strategy: validation

Validate before calling

// Validate the digest buffer before calling finish_blocking
let required = <A as DigestAlgorithm>::DIGEST_WORDS * 4;
if digest.len() < required {
    return Err(DigestBufferTooSmall { required, actual: digest.len() });
}

Prevention

When it happens

Trigger: Calling Hash::finish_blocking (or new_blocking/start/finish flows ending in finish_blocking) with a digest buffer smaller than digest_len_bytes for the selected algorithm — e.g. a [u8; 16] buffer for SHA-256 which needs 32 bytes.

Common situations: Buffer sized for MD5/SHA-1 (16/20 bytes) reused with a SHA-256 algorithm type; generic code that sizes the output buffer from a wrong constant; switching the hash algorithm type parameter without resizing the output array.

Related errors


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

Appendix: source

Thrown at embassy-stm32/src/hash/mod.rs:611

        // For HMAC, after message digest the peripheral waits for the outer key.
        if let Some(key) = H::key_ref(&ctx.key) {
            while !T::regs().sr().read().dinis() {}
            self.accumulate_blocking::<A>(key);
            T::regs().str().write(|w| w.set_dcal(true));
        }
        // Block until digest computation is complete.
        while !T::regs().sr().read().dcis() {}

        // The hardware no longer holds a resumable context. Clones of `ctx`
        // share its id, so they must not skip the restore in `load_context`.
        self.current_id = None;

        // Return the digest.
        let digest_words = A::DIGEST_WORDS;
        let digest_len_bytes = digest_words * 4;
        // Panics if the supplied digest buffer is too short.
        if digest.len() < digest_len_bytes {
            panic!("Digest buffer must be at least {} bytes long.", digest_len_bytes);
        }

        let mut hr = [0u32; 16];
        for i in 0..digest_words {
            hr[i] = T::regs().hr(i).read();
        }
        for i in 0..digest_words {
            let word = hr[i];
            digest[(i * 4)..((i * 4) + 4)].copy_from_slice(word.to_be_bytes().as_slice());
        }

        digest_len_bytes
    }

    /// HMAC of an empty message.
    ///
    /// The core ignores the message-phase DCAL when no data was written after
    /// the key phase, so it cannot compute this on its own (the ST HAL rejects

View on GitHub (pinned to 463a07b963)