rust-hmac-sha256

A small, self-contained SHA-256, HMAC-SHA256, and HKDF-SHA256 implementation in pure Rust with no_std support.

Library
Cargo
v1.1.14
38stars
ISC

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
24/100Needs Attention
Development Activity4
Maintenance0
Community20
Maturity60
Momentum12

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
58/100Fair
Architecture75
Code Quality55
Innovation50
Learning Curve50

hmac-sha256 is a minimal, dependency-free Rust crate that implements SHA-256, HMAC-SHA256, and HKDF-SHA256 from scratch in a single source file. It targets no_std environments — embedded systems, WASM targets, and other constrained runtimes — where pulling in the broader RustCrypto dependency tree isn’t practical. Both one-shot and streaming APIs are provided for computing hashes and MACs, along with constant-time verification helpers built specifically to resist timing-attack based key or data recovery.

The crate optionally implements the Digest trait from the digest crate (supporting versions 0.9.0, 0.10.7, and 0.11.0 simultaneously via separate feature flags) so it can be used as a drop-in hasher wherever the RustCrypto trait ecosystem is expected, while staying dependency-free by default. An opt_size feature further shrinks the compiled .text section by roughly 75% at a documented ~16% runtime cost, aimed at size-constrained embedded targets.

What You Get

  • One-shot and streaming APIs for SHA-256 hashing (Hash::hash, Hash::new/update/finalize)
  • One-shot and streaming HMAC-SHA256 computation (HMAC::mac, HMAC::new/update/finalize)
  • RFC 5869 HKDF-SHA256 key derivation via HKDF::extract and HKDF::expand
  • Constant-time verification helpers (finalize_verify, verify) to prevent timing side-channels
  • Optional Digest trait implementations for digest 0.9, 0.10, and 0.11 behind feature flags
  • An opt_size feature for reducing binary size on embedded targets

Common Use Cases

  • Computing SHA-256 checksums or HMAC-SHA256 signatures in no_std embedded firmware
  • Verifying webhook signatures or signed API requests in size-sensitive WASM builds
  • Deriving session or encryption keys from a shared secret via HKDF-SHA256
  • Providing a lightweight Digest-trait-compatible hasher for crates that expect the RustCrypto interface without pulling in the full sha2 dependency tree

Under The Hood

Architecture The crate is organized as a single lib.rs implementing a layered Merkle–Damgård construction: low-level State/W structs perform 64-byte block compression, the public Hash struct wraps that state machine with a streaming update/finalize API, HMAC composes two Hash instances around inner/outer key padding per the standard HMAC construction, and HKDF is built entirely on top of HMAC::mac for its extract/expand steps. Three feature-gated submodules (digest_trait09, digest_trait010, digest_trait011) each implement the RustCrypto Digest trait family against the same underlying Hash type, letting one implementation serve three incompatible major versions of that ecosystem’s trait simultaneously without duplicating core logic.

Tech Stack Built against the 2021 Rust edition with #![no_std] and zero mandatory dependencies. The only dependencies (digest09, digest010, digest011, all optional and each pinned to one digest crate release) are gated behind matching traits09/traits010/traits011 feature flags for RustCrypto interop; the default build pulls in nothing external. There is no build script, no async runtime, and no I/O — the entire crate is pure computation over byte slices, published to crates.io as hmac-sha256.

Code Quality A single #[test] fn main() embedded in lib.rs exercises HMAC, HKDF, and verification paths against hardcoded known-answer test vectors; a separate tests/test_digest011.rs file covers the Digest trait implementation (chaining, reset, one-shot digest). There are no typed errors — HKDF::expand panics via assert! if the requested output exceeds 255×32 bytes, which is standard for a low-level no_std primitive but does mean misuse surfaces as a panic rather than a Result. No CI workflow is present in the repository (only a Dependabot config for dependency updates), so tests are not automatically run on every change; naming is consistent and inline doc comments are used throughout the public API, with #![allow(...)] clippy lint overrides suggesting clippy is run informally during development.

API Design The public surface is intentionally narrow and consistent: Hash, HMAC, and HKDF each expose a matching one-shot convenience function alongside an incremental new/update/finalize pair, so callers can pick whichever shape fits their control flow without learning different idioms per primitive. Every public method carries a doc comment with a runnable example, and impl AsRef<[u8]> parameters let callers pass byte slices, arrays, or Vec<u8> interchangeably without explicit conversions. The tradeoff for that simplicity is standard-spec functionality only — SHA-256/HMAC-SHA256/HKDF-SHA256 exactly as defined by NIST and RFC 5869, with no algorithm agility, but a genuinely low-boilerplate onramp for the one job it does.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search