Collection of cryptographic hash functions written in pure Rust.
All algorithms reside in separate crates and are implemented using traits from digest
crate.
Additionally all crates do not require the standard library (i.e. no_std
capable) and can be easily used for bare-metal or WebAssembly programming.
Note: For new applications, or where compatibility with other existing standards is not a primary concern, we strongly recommend to use either BLAKE2, SHA-2 or SHA-3.
Algorithm | Crate | Crates.io | Documentation | MSRV | Security |
---|---|---|---|---|---|
Ascon hash | [ascon-hash ] |
π | |||
BelT hash | belt-hash |
π | |||
BLAKE2 | blake2 |
π | |||
FSB | fsb |
π | |||
GOST R 34.11-94 | gost94 |
π | |||
GrΓΈstl (Groestl) | groestl |
π | |||
KangarooTwelve | k12 |
π | |||
MD2 | md2 |
π | |||
MD4 | md4 |
π | |||
MD5 | md5 β |
π | |||
RIPEMD | ripemd |
π | |||
SHA-1 | sha1 |
π | |||
SHA-2 | sha2 |
π | |||
SHA-3 (Keccak) | sha3 |
π | |||
SHABAL | shabal |
π | |||
SM3 (OSCCA GM/T 0004-2012) | sm3 |
π | |||
Streebog (GOST R 34.11-2012) | streebog |
π | |||
Tiger | tiger |
π | |||
Whirlpool | whirlpool |
π |
NOTE: the blake3
crate implements the digest
traits used by the rest of the hashes in this repository, but is maintained by the BLAKE3 team.
The following describes the security level ratings associated with each hash function (i.e. algorithms, not the specific implementation):
Heart | Description |
---|---|
π | No known successful attacks |
π | Theoretical break: security lower than claimed |
π | Attack demonstrated in practice: avoid if at all possible |
See the Security page on Wikipedia for more information.
Whenever possible crates are published under the same name as the crate folder.
Owners of md5
declined to participate in this project.
This crate does not implement the digest
traits, so it is not interoperable with the RustCrypto ecosystem.
This is why we publish our MD5 implementation as md-5
and mark it with the β mark.
Note that the library itself is named as md5
, i.e. inside use
statements you should use md5
, not md_5
.
The SHA-1 implementation was previously published as sha-1
, but migrated to sha1
since v0.10.0.
sha-1
will continue to receive v0.10.x patch updates, but will be deprecated after sha1
v0.11 release.
MSRV bumps are considered breaking changes and will be performed only with minor version bump.
Let us demonstrate how to use crates in this repository using SHA-2 as an example.
First add sha2
crate to your Cargo.toml
:
[dependencies]
sha2 = "0.10"
Note that all crates in this repository have an enabled by default std
feature.
So if you plan to use the crate in no_std
environments, don't forget to disable it:
[dependencies]
sha2 = { version = "0.10", default-features = false }
sha2
and the other hash implementation crates re-export the digest
crate and the Digest
trait for convenience, so you don't have to include it in your Cargo.toml
it as an explicit dependency.
Now you can write the following code:
use sha2::{Sha256, Digest};
let mut hasher = Sha256::new();
let data = b"Hello world!";
hasher.update(data);
// `update` can be called repeatedly and is generic over `AsRef<[u8]>`
hasher.update("String data");
// Note that calling `finalize()` consumes hasher
let hash = hasher.finalize();
println!("Binary hash: {:?}", hash);
In this example hash
has type GenericArray<u8, U32>
, which is a generic alternative to [u8; 32]
defined in the generic-array
crate.
If you need to serialize hash value into string, you can use crates like base16ct
and base64ct
:
use base64ct::{Base64, Encoding};
let base64_hash = Base64::encode_string(&hash);
println!("Base64-encoded hash: {}", base64_hash);
let hex_hash = base16ct::lower::encode_string(&hash);
println!("Hex-encoded hash: {}", hex_hash);
Instead of calling update
, you also can use a chained approach:
use sha2::{Sha256, Digest};
let hash = Sha256::new()
.chain_update(b"Hello world!")
.chain_update("String data")
.finalize();
If a complete message is available, then you can use the convenience Digest::digest
method:
use sha2::{Sha256, Digest};
let hash = Sha256::digest(b"my message");
If you want to hash data from a type which implements the Read
trait, you can rely on implementation of the Write
trait (requires enabled-by-default std
feature):
use sha2::{Sha256, Digest};
use std::{fs, io};
let mut file = fs::File::open(&path)?;
let mut hasher = Sha256::new();
let n = io::copy(&mut file, &mut hasher)?;
let hash = hasher.finalize();
If you want to calculate Hash-based Message Authentication Code (HMAC), you can use the generic implementation from hmac
crate, which is a part of the RustCrypto/MACs repository.
You can write generic code over the Digest
trait (or other traits from the digest
crate) which will work over different hash functions:
use sha2::{Sha256, Sha512, Digest};
// Toy example, do not use it in practice!
// Instead use crates from: https://github.com/RustCrypto/password-hashing
fn hash_password<D: Digest>(password: &str, salt: &str, output: &mut [u8]) {
let mut hasher = D::new();
hasher.update(password.as_bytes());
hasher.update(b"$");
hasher.update(salt.as_bytes());
output.copy_from_slice(&hasher.finalize())
}
let mut buf1 = [0u8; 32];
hash_password::<Sha256>("my_password", "abcd", &mut buf1);
let mut buf2 = [0u8; 64];
hash_password::<Sha512>("my_password", "abcd", &mut buf2);
If you want to use hash functions with trait objects, you can use the DynDigest
trait:
use digest::DynDigest;
// Dynamic hash function
fn use_hasher(hasher: &mut dyn DynDigest, data: &[u8]) -> Box<[u8]> {
hasher.update(data);
hasher.finalize_reset()
}
// You can use something like this when parsing user input, CLI arguments, etc.
// DynDigest needs to be boxed here, since function return should be sized.
fn select_hasher(s: &str) -> Box<dyn DynDigest> {
match s {
"md5" => Box::new(md5::Md5::default()),
"sha1" => Box::new(sha1::Sha1::default()),
"sha224" => Box::new(sha2::Sha224::default()),
"sha256" => Box::new(sha2::Sha256::default()),
"sha384" => Box::new(sha2::Sha384::default()),
"sha512" => Box::new(sha2::Sha512::default()),
_ => unimplemented!("unsupported digest: {}", s),
}
}
let mut hasher1 = select_hasher("md5");
let mut hasher2 = select_hasher("sha512");
// the `&mut *hasher` is to DerefMut the value out of the Box
// this is equivalent to `DerefMut::deref_mut(&mut hasher)`
// can be reused due to `finalize_reset()`
let hash1_1 = use_hasher(&mut *hasher1, b"foo");
let hash1_2 = use_hasher(&mut *hasher1, b"bar");
let hash2_1 = use_hasher(&mut *hasher2, b"foo");
All crates licensed under either of
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.