big_hash/
lib.rs

1//! Compute MD5, SHA256, and SHA512 hashes of data through the `core::hash` 
2//! API.
3//! 
4//! ## Be warned that:
5//!
6//! - `core::hash` implementations are not necessarily consistent 
7//!   cross-platform, for example, they may use native-endianness,
8//!   or be dependent on implementation details of things like 
9//!   `OsString`.
10//! - [MD5 should be considered cryptographically broken and unsuitable
11//!   for cryptographic use.][1]
12//!
13//! [1]: https://github.com/stainless-steel/md5#security-warning
14
15#![no_std]
16
17use core::{
18    hash::{Hash, Hasher},
19    convert::TryFrom,
20};
21
22/// Compute an MD5 digest through the `core::hash` API.
23///
24/// # Security Warning
25/// 
26/// MD5 should be considered cryptographically broken and unsuitable
27/// for cryptographic use. 
28#[cfg(feature = "hash-md5")]
29pub fn md5_hash<H: Hash>(data: &H) -> [u8; 16] {
30    let mut hasher = md5_hasher::Md5Hasher::new();
31    data.hash(&mut hasher);
32    hasher.digest()
33}
34
35#[cfg(feature = "hash-md5")]
36#[doc(opaque)]
37pub use md5_hasher::Md5Hasher;
38
39/// Compute an SHA256 hash through the `core::hash` API.
40#[cfg(feature = "hash-sha256")]
41pub fn sha256_hash<H: Hash>(data: &H) -> [u8; 32] {
42    let mut hasher = sha256_hasher::Sha256Hasher::new();
43    data.hash(&mut hasher);
44    hasher.finalize()
45}
46
47#[cfg(feature = "hash-sha256")]
48#[doc(opaque)]
49pub use sha256_hasher::Sha256Hasher;
50
51/// Compute an SHA512 hash through the `core::hash` API.
52#[cfg(feature = "hash-sha512")]
53pub fn sha512_hash<H: Hash>(data: &H) -> [u8; 64] {
54    let mut hasher = sha512_hasher::Sha512Hasher::new();
55    data.hash(&mut hasher);
56    hasher.finalize()
57}
58
59#[cfg(feature = "hash-sha512")]
60#[doc(opaque)]
61pub use sha512_hasher::Sha512Hasher;
62
63/// Input size must be a multiple of 8.
64fn bytes_xor_u64(slice: &[u8]) -> u64 {
65    assert_eq!(slice.len() % 8, 0);
66
67    let mut accum: u64 = 0;
68    for i in 0..slice.len() / 8 {
69        let subslice = &slice[i * 8..(i + 1) * 8];
70        let subslice = <[u8; 8]>::try_from(subslice).unwrap();
71        accum ^= u64::from_ne_bytes(subslice);
72    }
73
74    accum
75}
76
77#[cfg(feature = "hash-md5")]
78mod md5_hasher {
79    extern crate md5;
80    use super::*;
81
82    /// Glue between `core::hash` and `md5`.
83    #[derive(Clone)]
84    pub struct Md5Hasher(md5::Context);
85
86    impl Md5Hasher {
87        pub fn new() -> Self {
88            Md5Hasher(md5::Context::new())
89        }
90
91        /// Digest the data into an MD5 hash.
92        pub fn digest(&self) -> [u8; 16] {
93            self.0.clone().compute().into()
94        }
95    }
96
97    impl Hasher for Md5Hasher {
98        fn finish(&self) -> u64 {
99            bytes_xor_u64(&self.digest())
100        }
101
102        fn write(&mut self, bytes: &[u8]) {
103            self.0.consume(bytes);
104        }
105    }
106}
107
108#[cfg(feature = "hash-sha256")]
109mod sha256_hasher {
110    extern crate hmac_sha256;
111
112    use super::*;
113    use hmac_sha256 as sha256;
114
115    /// Glue between `core::hash` and `hmac_sha256`.
116    #[derive(Copy, Clone)]
117    pub struct Sha256Hasher(sha256::Hash);
118
119    impl Sha256Hasher {
120        pub fn new() -> Self {
121            Sha256Hasher(sha256::Hash::new())
122        }
123
124        /// Compute the SHA256 hash.
125        pub fn finalize(&self) -> [u8; 32] {
126            self.0.finalize()
127        }
128    }
129
130    impl Hasher for Sha256Hasher {
131        fn finish(&self) -> u64 {
132            bytes_xor_u64(&self.finalize())
133        }
134
135        fn write(&mut self, bytes: &[u8]) {
136            self.0.update(bytes);
137        }
138    }
139}
140
141#[cfg(feature = "hash-sha512")]
142mod sha512_hasher {
143    extern crate hmac_sha512;
144
145    use super::*;
146    use hmac_sha512 as sha512;
147
148    /// Glue between `core::hash` and `hmac_sha512`.
149    #[derive(Copy, Clone)]
150    pub struct Sha512Hasher(sha512::Hash);
151
152    impl Sha512Hasher {
153        pub fn new() -> Self {
154            Sha512Hasher(sha512::Hash::new())
155        }
156
157        /// Compute the SHA512 hash.
158        pub fn finalize(&self) -> [u8; 64] {
159            self.0.finalize()
160        }
161    }
162
163    impl Hasher for Sha512Hasher {
164        fn finish(&self) -> u64 {
165            bytes_xor_u64(&self.finalize())
166        }
167
168        fn write(&mut self, bytes: &[u8]) {
169            self.0.update(bytes);
170        }
171    }
172}
173