ya_md5/lib.rs
1#![warn(missing_docs)]
2
3//! An implementation of the [MD5] hash algorithm capable to hash data readed from a
4//! [std::io::Read] implementation.
5//!
6//! ## Example
7//! ```rust
8//! use std::fs::File;
9//! use std::io::prelude::*;
10//! use ya_md5::Md5Hasher;
11//! use ya_md5::Hash;
12//! use ya_md5::Md5Error;
13//!
14//! fn example() -> Result<(), Md5Error> {
15//! std::fs::write("foo.txt", b"hello world")?;
16//! let hash = {
17//! let mut file = File::open("foo.txt")?;
18//! Md5Hasher::hash(&mut file)?
19//! };
20//! std::fs::remove_file("foo.txt")?;
21//! let result = format!("{}", hash);
22//! assert_eq!(result, "5eb63bbbe01eeed093cb22bb8f5acdc3");
23//! Ok(())
24//! }
25//! ```
26//!
27//! [MD5]: https://en.wikipedia.org/wiki/MD5
28
29mod chunk;
30mod chunk_processor;
31mod conversions;
32mod hash;
33mod hash_compute_state;
34mod md5_error;
35
36use chunk::CHUNK_SIZE_BYTES;
37
38pub use crate::hash::Hash;
39pub use crate::md5_error::Md5Error;
40
41use crate::chunk_processor::ChunkProcessor;
42
43use std::io::Read;
44
45/// A hasher thath computes the MD5 hash of a given list of chunks.
46///
47/// Each chunk is defined as a buffer of type `[u8; 64]`.
48///
49/// Provides conveniente functions to compute the MD5 hash of various sources without having to
50/// create and manage an instance.
51#[derive(Default)]
52pub struct Md5Hasher {
53 processor: ChunkProcessor,
54}
55
56impl Md5Hasher {
57 /// Computes and returns the hash of the data that can be readed from the `input`.
58 ///
59 /// # Errors
60 ///
61 /// If there's any I/O error while reading the `input` an error is returned.
62 ///
63 /// # Examples
64 ///
65 /// ```
66 /// use std::io::Cursor;
67 /// use ya_md5::Md5Hasher;
68 ///
69 /// let hash = Md5Hasher::hash(&mut Cursor::new("hello world".as_bytes()))
70 /// .expect("Unexpected error reading from a cursor");
71 /// let result = format!("{}", hash);
72 /// assert_eq!(result, "5eb63bbbe01eeed093cb22bb8f5acdc3");
73 /// ```
74 pub fn hash(input: &mut dyn Read) -> Result<Hash, Md5Error> {
75 let mut hasher = Self::default();
76 let mut buffer = [0; CHUNK_SIZE_BYTES];
77 loop {
78 let readed = input.read(&mut buffer).map_err(Md5Error::from)?;
79 if readed == 0 {
80 break;
81 }
82 hasher.update(&buffer[..readed]);
83 }
84 Ok(hasher.finalize())
85 }
86
87 /// Computes and returns the hash of the data in the slice.
88 ///
89 /// # Examples
90 /// ```
91 /// use ya_md5::Md5Hasher;
92 ///
93 /// let hash = Md5Hasher::hash_slice("hello world".as_bytes());
94 /// let result = format!("{}", hash);
95 /// assert_eq!(result, "5eb63bbbe01eeed093cb22bb8f5acdc3");
96 /// ```
97 pub fn hash_slice(data: &[u8]) -> Hash {
98 let mut hasher = Self::default();
99 hasher.update(data);
100 hasher.finalize()
101 }
102
103 /// Computes and returns the hash of the data in the `Vec`.
104 ///
105 /// # Examples
106 ///
107 /// ```
108 /// use ya_md5::Md5Hasher;
109 ///
110 /// let hash = Md5Hasher::hash_vec(&Vec::from("hello world".as_bytes()));
111 /// let result = format!("{}", hash);
112 /// assert_eq!(result, "5eb63bbbe01eeed093cb22bb8f5acdc3");
113 /// ```
114 pub fn hash_vec(data: &Vec<u8>) -> Hash {
115 Self::hash_slice(data.as_slice())
116 }
117
118 /// Computes and returns the hash of the data in the string slice.
119 ///
120 /// # Examples
121 /// ```
122 /// use ya_md5::Md5Hasher;
123 ///
124 /// let hash = Md5Hasher::hash_str("hello world");
125 /// let result = format!("{}", hash);
126 /// assert_eq!(result, "5eb63bbbe01eeed093cb22bb8f5acdc3");
127 /// ```
128 pub fn hash_str(data: &str) -> Hash {
129 Self::hash_slice(data.as_bytes())
130 }
131
132 /// Process a single chunk and use it to compute the internal state.
133 pub fn update(&mut self, data: impl AsRef<[u8]>) {
134 self.processor.update(data);
135 }
136
137 /// Computes the hash of the internal state of the instance, consuming the instance in the
138 /// process.
139 pub fn finalize(self) -> Hash {
140 self.processor.finalize()
141 }
142}