crypt-sha512
A no_std-compatible Rust implementation of the SHA512-crypt password
hashing algorithm ($6$ Unix crypt format), ported from
Ulrich Drepper's reference C implementation.
The four cryptographic primitives this crate needs — SHA-512, a CSPRNG, a constant-time comparison, and a non-elidable memory wipe — are delegated to a backend selected at build time via cargo features. This lets the crate slot into projects that have already standardized on a particular crypto stack without dragging in a second one.
Backend selection
Exactly one of the following features must be enabled. There is no default; selecting zero or more than one is a compile error.
| Feature | Stack | Build requirements |
|---|---|---|
backend-aws-lc |
aws-lc-sys |
C compiler, cmake |
backend-boring |
boring-sys (BoringSSL) |
C/C++ compiler, cmake, go |
backend-openssl |
openssl-sys |
OpenSSL headers/libs (libssl-dev / brew install openssl) |
backend-rust-crypto |
sha2 + getrandom + subtle + zeroize |
none (pure Rust) |
The public API is identical regardless of backend; switching is a manifest-only change.
Features
no_std-compatible — only requiresalloc.- Auto-zeroizing input type — passwords are passed as a [
Password] newtype whoseDropimpl wipes the backing buffer with the backend's non-elidable zeroing primitive (OPENSSL_cleansefor the FFI backends,zeroize::Zeroizeforbackend-rust-crypto). - Timing-attack resistant — verification compares with the backend's
constant-time
memcmp. - Cryptographically secure salts — generated with the backend's CSPRNG.
- Unix
$6$compatible — output is bit-identical to glibc / libxcrypt.
Usage
[]
= { = "1.0.0", = false, = ["backend-aws-lc"] }
Hash a new password
use ;
// Default work factor (5000 rounds), random salt
let h = hash;
// Higher work factor for more sensitive deployments
let h = hash;
Verify a password
use ;
let stored = hash;
assert_eq!;
assert_eq!;
// Malformed hash strings are reported separately from a wrong password.
assert_eq!;
verify distinguishes three outcomes:
Ok(true)— the hash parses and the password matches.Ok(false)— the hash parses and the password does not match.Err(InvalidHash)— the hash string is malformed; no comparison was performed. Useful for handling multiple hash types or detecting data corruption separately from authentication failures.
Hash with an explicit salt (low-level)
For interoperability tests or when you need to control the salt directly:
use ;
let h = hash_with_salt;
assert!;
The Password type
Password is the only way to feed plaintext into this crate's hashing
functions. It deliberately:
- accepts
From<String>,From<&str>,From<Vec<u8>>, andPassword::from_bytes; - does not implement
Clone, so secrets aren't silently duplicated; - does not implement
Display, and itsDebugimpl elides the contents, so secrets can't accidentally land in logs; - zeroes its buffer with the active backend's non-elidable zeroing primitive on drop — including on panic.
Pass it by value into hash, hash_with_salt, or verify; the function
takes ownership and the buffer is wiped before the call returns.
Hash format
$6$[rounds=N$]salt$digest
$6$— SHA512-crypt identifier.rounds=N$— optional; default is 5000. Values are clamped into[1000, 999_999_999]per the SHA-crypt spec.salt— up to 16 bytes from the crypt base64 alphabet.digest— 86 bytes, crypt base64.
MSRV
Rust 1.81.
License
BSD 2-Clause. See the LICENSE file in the repository.
Provenance
The hashing algorithm is a direct port of Ulrich Drepper's public-domain
SHA-crypt reference implementation. The b64_from_24bit macro mirrors the
shape of the original C macro; tests reuse Drepper's published vectors.