1#![allow(clippy::indexing_slicing)]
10#![deny(clippy::integer_division_remainder_used)]
11
12use crate::cfg_feature_alloc;
13pub use blake2::*;
14use core::ops::BitXorAssign;
15use irox_bits::MutBits;
16pub use md5::MD5;
17pub use murmur3::{murmur3_128, murmur3_128_seed};
18pub use sha1::SHA1;
19pub use sha2::{SHA224, SHA256, SHA384, SHA512};
20
21mod blake2;
22pub mod md5;
23pub mod murmur3;
24pub mod sha1;
25pub mod sha2;
26pub mod sixwords;
27pub mod viz;
28
29pub trait HashDigest<const BLOCK_SIZE: usize, const OUTPUT_SIZE: usize>: Default {
31 fn write(&mut self, bytes: &[u8]);
32 fn hash(self, bytes: &[u8]) -> [u8; OUTPUT_SIZE];
33 fn finish(self) -> [u8; OUTPUT_SIZE];
34 fn algorithm() -> HashAlgorithm;
35}
36
37pub type HMACSHA1 = HMAC<{ sha1::BLOCK_SIZE }, { sha1::OUTPUT_SIZE }, sha1::SHA1>;
39pub type HMACMD5 = HMAC<{ md5::BLOCK_SIZE }, { md5::OUTPUT_SIZE }, md5::MD5>;
41pub type HMACSHA224 = HMAC<{ sha2::SHA224_BLOCK_SIZE }, { sha2::SHA224_OUTPUT_SIZE }, sha2::SHA224>;
43pub type HMACSHA256 = HMAC<{ sha2::SHA256_BLOCK_SIZE }, { sha2::SHA256_OUTPUT_SIZE }, sha2::SHA256>;
45pub type HMACSHA384 = HMAC<{ sha2::SHA384_BLOCK_SIZE }, { sha2::SHA384_OUTPUT_SIZE }, sha2::SHA384>;
47pub type HMACSHA512 = HMAC<{ sha2::SHA512_BLOCK_SIZE }, { sha2::SHA512_OUTPUT_SIZE }, sha2::SHA512>;
49pub type HMACBLAKE2s = HMAC<64, 32, BLAKE2s256>;
51pub type HMACBLAKE2b = HMAC<128, 64, BLAKE2b512>;
53
54pub struct HMAC<
60 const BLOCK_SIZE: usize,
61 const OUTPUT_SIZE: usize,
62 T: HashDigest<BLOCK_SIZE, OUTPUT_SIZE>,
63> {
64 opad: [u8; BLOCK_SIZE],
65 alg: T,
66}
67
68impl<const BLOCK_SIZE: usize, const OUTPUT_SIZE: usize, T: HashDigest<BLOCK_SIZE, OUTPUT_SIZE>>
69 HMAC<BLOCK_SIZE, OUTPUT_SIZE, T>
70{
71 pub fn new(in_key: &[u8]) -> Self {
73 let keylen = in_key.len();
74 let mut key = [0u8; BLOCK_SIZE];
75 if keylen > BLOCK_SIZE {
76 let hash = T::default().hash(in_key) as [u8; OUTPUT_SIZE];
77
78 let _ = key.as_mut_slice().write_all_bytes(&hash);
79 } else {
80 let _ = key.as_mut_slice().write_all_bytes(in_key);
81 }
82 let mut ipad = [0x36u8; BLOCK_SIZE];
83 let mut opad = [0x5Cu8; BLOCK_SIZE];
84 let mut alg = T::default();
85
86 for idx in 0..BLOCK_SIZE {
87 let k = key[idx];
88 ipad[idx].bitxor_assign(k);
89 opad[idx].bitxor_assign(k);
90 }
91 alg.write(ipad.as_slice());
92
93 Self { alg, opad }
94 }
95
96 pub fn write(&mut self, bytes: &[u8]) {
97 self.alg.write(bytes)
98 }
99 pub fn hash(mut self, bytes: &[u8]) -> [u8; OUTPUT_SIZE] {
102 self.write(bytes);
103 self.finish()
104 }
105 pub fn finish(self) -> [u8; OUTPUT_SIZE] {
108 let Self { alg, opad } = self;
109 let inner = alg.finish();
110
111 let mut outer = T::default();
112 outer.write(&opad);
113 outer.hash(&inner)
114 }
115}
116
117#[non_exhaustive]
118#[derive(Debug, Copy, Clone, Eq, PartialEq)]
119pub enum HashAlgorithm {
120 MD5,
121 SHA1,
122 SHA224,
123 SHA256,
124 SHA384,
125 SHA512,
126 Murmur3_128,
127 Murmur3_32,
128 BLAKE2s128,
129 BLAKE2s160,
130 BLAKE2s224,
131 BLAKE2s256,
132 BLAKE2b160,
133 BLAKE2b224,
134 BLAKE2b256,
135 BLAKE2b384,
136 BLAKE2b512,
137}
138impl TryFrom<&str> for HashAlgorithm {
139 type Error = ();
140
141 fn try_from(value: &str) -> Result<Self, Self::Error> {
142 Ok(match value {
143 "md5" => Self::MD5,
144 "sha1" => Self::SHA1,
145 "sha256" => Self::SHA256,
146 "sha512" => Self::SHA512,
147 "murmur3_128" | "murmur3" | "m3" => Self::Murmur3_128,
148 "b2" | "b2b" | "blake2b" | "blake2b512" => Self::BLAKE2b512,
149 "b2s" | "blake2s" | "blake2s256" => Self::BLAKE2s256,
150 _ => return Err(()),
151 })
152 }
153}
154
155cfg_feature_alloc! {
156 extern crate alloc;
157 use irox_bits::{Error, ToBEBytes};
158 use crate::hash::murmur3::{Murmur3_128, Murmur3_32};
159
160 pub struct HasherCounting {
161 pub count: u64,
162 pub hasher: Hasher,
163 }
164 impl HasherCounting {
165 pub fn write(&mut self, val: &[u8]) {
166 self.count += val.len() as u64;
167 self.hasher.write(val);
168 }
169 pub fn count(&self) -> u64 {
170 self.count
171 }
172 pub fn finish(self) -> (u64, alloc::boxed::Box<[u8]>) {
173 (self.count, self.hasher.finish())
174 }
175 }
176 impl MutBits for HasherCounting {
177 fn write_u8(&mut self, val: u8) -> Result<(), Error> {
178 self.write(&[val]);
179 Ok(())
180 }
181 fn write_all_bytes(&mut self, val: &[u8]) -> Result<(), Error> {
182 self.write(val);
183 Ok(())
184 }
185 }
186
187 impl TryFrom<HashAlgorithm> for HasherCounting {
188 type Error = Error;
189 fn try_from(value: HashAlgorithm) -> Result<Self, Self::Error> {
190 Ok(HasherCounting {
191 count: 0,
192 hasher: value.try_into()?
193 })
194 }
195 }
196
197 #[derive(Clone)]
198 pub enum Hasher {
199 MD5(MD5),
200 SHA1(SHA1),
201 SHA224(SHA224),
202 SHA256(SHA256),
203 SHA384(SHA384),
204 SHA512(SHA512),
205 Murmur3_128(Murmur3_128),
206 Murmur3_32(Murmur3_32),
207 BLAKE2b512(BLAKE2b512),
208 BLAKE2s256(BLAKE2s256),
209 BLAKE2s128(BLAKE2s128),
210 BLAKE2s160(BLAKE2s160),
211 BLAKE2s224(BLAKE2s224),
212 BLAKE2b160(BLAKE2b160),
213 BLAKE2b224(BLAKE2b224),
214 BLAKE2b256(BLAKE2b256),
215 BLAKE2b384(BLAKE2b384),
216 }
217 macro_rules! impl_hash_from {
218 ($value:ident, [$($hash:ident),+]) => {
219 match $value {
220 $(
221 HashAlgorithm::$hash => Ok(Hasher::$hash(<$hash>::default())),
222 )*
223 _ => todo!()
224 }
225 };
226 }
227 impl TryFrom<HashAlgorithm> for Hasher {
228 type Error = Error;
229
230 fn try_from(value: HashAlgorithm) -> Result<Self, Self::Error> {
231 impl_hash_from!(value,
232 [
233 MD5, SHA1, SHA256, SHA384, SHA512, Murmur3_128, Murmur3_32,
234 BLAKE2s128, BLAKE2s160, BLAKE2s224, BLAKE2s256,
235 BLAKE2b160, BLAKE2b224, BLAKE2b256, BLAKE2b384, BLAKE2b512
236 ])
237 }
238 }
239 macro_rules! impl_hash_write {
240 ($value:ident, $val:ident, [$($hash:ident),+]) => {
241 match $value {
242 $(
243 Hasher::$hash(h) => h.write($val),
244 )*
245 _ => todo!()
246 }
247 };
248 }
249
250 macro_rules! impl_hash_finish {
251 ($value:ident, [$($hash:ident),+]) => {
252 match $value {
253 $(
254 Hasher::$hash(v) => alloc::boxed::Box::from(v.finish().to_be_bytes()),
255 )*
256 _ => todo!()
257 }
258 };
259 }
260 impl Hasher {
261 pub fn write(&mut self, val: &[u8]) {
262 impl_hash_write!(self, val,
263 [
264 MD5, SHA1, SHA256, SHA384, SHA512, Murmur3_128, Murmur3_32,
265 BLAKE2s128, BLAKE2s160, BLAKE2s224, BLAKE2s256,
266 BLAKE2b160, BLAKE2b224, BLAKE2b256, BLAKE2b384, BLAKE2b512
267 ])
268 }
269 pub fn finish(self) -> alloc::boxed::Box<[u8]> {
270 impl_hash_finish!(self,
271 [
272 MD5, SHA1, SHA256, SHA384, SHA512, Murmur3_128, Murmur3_32,
273 BLAKE2s128, BLAKE2s160, BLAKE2s224, BLAKE2s256,
274 BLAKE2b160, BLAKE2b224, BLAKE2b256, BLAKE2b384, BLAKE2b512
275 ])
276 }
277 crate::cfg_feature_std! {
278 pub fn hash_file<T: AsRef<std::path::Path>>(&mut self, path: T) -> Result<(), std::io::Error> {
279 use std::io::Read;
280 let mut file = std::fs::OpenOptions::new()
281 .read(true)
282 .create(false)
283 .open(path)?;
284 let mut buffer = <alloc::boxed::Box<[u8]> as crate::buf::ZeroedBuffer>::new_zeroed(32768);
285 loop {
286 let read = file.read(&mut buffer)?;
287 if read == 0 {
288 break;
289 }
290 if let Some(buf) = buffer.get(..read) {
291 self.write(buf);
292 }
293 }
294 Ok(())
295 }
296 }
297 }
298 impl MutBits for Hasher {
299 fn write_u8(&mut self, val: u8) -> Result<(), Error> {
300 self.write(&[val]);
301 Ok(())
302 }
303 fn write_all_bytes(&mut self, val: &[u8]) -> Result<(), Error> {
304 self.write(val);
305 Ok(())
306 }
307 }
308 crate::cfg_feature_std! {
309 impl HashAlgorithm {
310 pub fn hash_file<T: AsRef<std::path::Path>>(&self, path: T) -> Result<alloc::boxed::Box<[u8]>, Error> {
311 let mut hasher : Hasher = (*self).try_into()?;
312 hasher.hash_file(path)?;
313 Ok(hasher.finish())
314 }
315 }
316
317 }
318}
319#[cfg(test)]
320mod hmac_tests {
321 use crate::hash::*;
322
323 #[test]
324 pub fn wikitest1() {
325 assert_eq_hex_slice!(
326 0x80070713463e7749b90c2dc24911e275u128.to_be_bytes(),
327 HMACMD5::new("key".as_bytes())
328 .hash("The quick brown fox jumps over the lazy dog".as_bytes())
329 );
330 }
331
332 #[test]
333 pub fn wikitest2() {
334 assert_eq_hex_slice!(
335 [
336 0xde, 0x7c, 0x9b, 0x85, 0xb8, 0xb7, 0x8a, 0xa6, 0xbc, 0x8a, 0x7a, 0x36, 0xf7, 0x0a,
337 0x90, 0x70, 0x1c, 0x9d, 0xb4, 0xd9
338 ],
339 HMACSHA1::new("key".as_bytes())
340 .hash("The quick brown fox jumps over the lazy dog".as_bytes())
341 );
342 }
343
344 #[test]
345 pub fn rfctest1() {
346 assert_eq_hex_slice!(
347 0x9294727a3638bb1c13f48ef8158bfc9d_u128.to_be_bytes(),
348 HMACMD5::new(&[0x0B; 16]).hash("Hi There".as_bytes())
349 );
350 }
351 #[test]
352 pub fn rfctest2() {
353 assert_eq_hex_slice!(
354 0x750c783e6ab0b503eaa86e310a5db738_u128.to_be_bytes(),
355 HMACMD5::new("Jefe".as_bytes()).hash("what do ya want for nothing?".as_bytes())
356 );
357 }
358 #[test]
359 pub fn rfctest3() {
360 assert_eq_hex_slice!(
361 0x56be34521d144c88dbb8c733f0e8b3f6_u128.to_be_bytes(),
362 HMACMD5::new(&[0xAA; 16]).hash(&[0xDD; 50])
363 );
364 }
365}