# Laguna audit: local SHA-256 padding fix (1.0.4) **Date:** 2026-09-17 **Mode:** local uncommitted changes vs `HEAD` **Scope:** `Cargo.toml`, `Cargo.lock`, `src/sha256.rs`, `tests/sha256.rs`, `tests/hmac.rs` **Diff:** 5 files, +74 / −21 **Verdict:** Correct. No bugs. Two minor suggestions addressed. ## Summary This change fixes a SHA-256 padding bug for messages whose length is 63 mod 64, bumps the crate from 1.0.3 to 1.0.4, adds regression tests, and removes the `publish = ["kellnr"]` restriction for crates.io publication. The old `pad_message` in `src/sha256.rs` used the condition `self.mbi < MB_SIZE - 1` to decide whether to write the `0x80` pad byte in the current block before zero-fill and block processing. When `mbi == 63` (i.e. the message is 63 mod 64 bytes), that condition was false, so position 63 was zero-filled instead of receiving `0x80`. The block was then processed with `message || 0x00`, and `0x80` was written at index 0 of the next block — producing a digest of `message || 0x00 || 0x80 || ...` instead of the correct `message || 0x80 || 0x00 || ...`. The new code always writes the pad byte at `self.mb[self.mbi]` first (safe because `update` flushes full blocks, so `mbi` is always `< MB_SIZE` on entry), then zero-fills and processes the current block only when the 8-byte length field no longer fits (`mbi > MB_SIZE - 8`). HMAC-SHA-256 was affected too, since its inner hash processes 64-byte ipad + message bytes; a 63-byte message makes the inner length 127 (63 mod 64). ## Verification - The six new test vectors match `sha256sum` and Python `hmac`/`hashlib` exactly: SHA-256 at lengths 55, 56, 63, 64, 65 bytes (all `a`), and HMAC-SHA-256 over a 63-byte message with the 20-byte `0x0b` key. - `cargo test` passes: 11 tests across unit, integration, and doc suites. - `cargo clippy --all-targets` is clean. ## Issues ### 1 — resolved — comment refinement: `src/sha256.rs:177` The branch comment originally restated the code ("Zero-fill and process it, then start a fresh block for the length"). Trimmed to state the *why*: ``` // Fewer than 8 bytes remain; flush this block and start // a fresh block for the length field. ``` ### 2 — resolved — comment refinement: `tests/hmac.rs:63` The test comment referenced "the length that triggered the padding bug" (bug history) rather than the invariant. Reworded to state the invariant: ``` // A 63-byte message makes the inner SHA-256 process 127 bytes // (64 key-pad + 63 message), which is 63 mod 64 — the boundary // where the pad byte must start a new block. ``` ## Packaging change Removing `publish = ["kellnr"]` from `Cargo.toml` is intentional so `cargo publish` targets crates.io for the 1.0.4 release. ## Counts | Severity | Count | State | |----------------|-------|------------| | bug | 0 | — | | suggestion | 2 | resolved | | packaging | 1 | intentional |