md6/
lib.rs

1//! An implementation of the [MD6 hash function](http://groups.csail.mit.edu/cis/md6), via FFI to reference implementation.
2//!
3//! For more information about MD6 visit its [official homepage](http://groups.csail.mit.edu/cis/md6).
4//!
5//! There are two APIs provided: one for single-chunk hashing and one for hashing of multiple data segments.
6//!
7//! # Examples
8//!
9//! Hashing a single chunk of data with a 256-bit MD6 hash function, then verifying the result.
10//!
11//! ```
12//! # use md6::Md6;
13//! # use std::iter::FromIterator;
14//! let mut result = [0; 32];
15//! md6::hash(256, b"The lazy fox jumps over the lazy dog", &mut result).unwrap();
16//!
17//! assert_eq!(Vec::from_iter(result.iter().map(|&i| i)),
18//!            vec![0xE4, 0x55, 0x51, 0xAA, 0xE2, 0x66, 0xE1, 0x48,
19//!                 0x2A, 0xC9, 0x8E, 0x24, 0x22, 0x9B, 0x3E, 0x90,
20//!                 0xDC, 0x06, 0x61, 0x77, 0xF8, 0xFB, 0x1A, 0x52,
21//!                 0x6E, 0x9D, 0xA2, 0xCC, 0x95, 0x71, 0x97, 0xAA]);
22//! ```
23//!
24//! Hashing multiple chunks of data with a 512-bit MD6 hash function, then verifying the result.
25//!
26//! ```
27//! # use md6::Md6;
28//! # use std::iter::FromIterator;
29//! let mut result = [0; 64];
30//! let mut state = Md6::new(512).unwrap();
31//!
32//! state.update("Zażółć ".as_bytes());
33//! state.update("gęślą ".as_bytes());
34//! state.update("jaźń".as_bytes());
35//!
36//! state.finalise(&mut result);
37//! assert_eq!(Vec::from_iter(result.iter().map(|&i| i)),
38//!            vec![0x92, 0x4E, 0x91, 0x6A, 0x01, 0x2C, 0x1A, 0x8D,
39//!                 0x0F, 0xB7, 0x9A, 0x4A, 0xD4, 0x9C, 0x55, 0x5E,
40//!                 0xBD, 0xCA, 0x59, 0xB8, 0x1B, 0x4C, 0x13, 0x41,
41//!                 0x2E, 0x32, 0xA5, 0xC9, 0x3B, 0x61, 0xAD, 0xB8,
42//!                 0x4D, 0xB3, 0xF9, 0x0C, 0x03, 0x51, 0xB2, 0x9E,
43//!                 0x7B, 0xAE, 0x46, 0x9F, 0x8D, 0x60, 0x5D, 0xED,
44//!                 0xFF, 0x51, 0x72, 0xDE, 0xA1, 0x6F, 0x00, 0xF7,
45//!                 0xB4, 0x82, 0xEF, 0x87, 0xED, 0x77, 0xD9, 0x1A]);
46//! ```
47//!
48//! Comparing result of single- and multi-chunk hash methods hashing the same effective message with a 64-bit MD6 hash
49//! function.
50//!
51//! ```
52//! # use md6::Md6;
53//! # use std::iter::FromIterator;
54//! let mut result_multi  = [0; 8];
55//! let mut result_single = [0; 8];
56//!
57//! let mut state = Md6::new(64).unwrap();
58//! state.update("Zażółć ".as_bytes());
59//! state.update("gęślą ".as_bytes());
60//! state.update("jaźń".as_bytes());
61//! state.finalise(&mut result_multi);
62//!
63//! md6::hash(64, "Zażółć gęślą jaźń".as_bytes(), &mut result_single).unwrap();
64//!
65//! assert_eq!(Vec::from_iter(result_multi .iter().map(|&i| i)),
66//!            Vec::from_iter(result_single.iter().map(|&i| i)));
67//! ```
68//!
69//! # Special thanks
70//!
71//! To all who support further development on [Patreon](https://patreon.com/nabijaczleweli), in particular:
72//!
73//!   * ThePhD
74//!   * Embark Studios
75
76extern crate libc;
77
78mod native;
79
80use std::error::Error;
81use std::fmt;
82use std::io;
83
84
85/// Helper result type containing `Md6Error`.
86pub type Result<T> = std::result::Result<T, Md6Error>;
87
88
89/// Hash all data in one fell swoop.
90///
91/// Refer to individual functions for extended documentation.
92///
93/// # Example
94///
95/// ```
96/// # use md6::Md6;
97/// # use std::iter::FromIterator;
98/// let mut result_256 = [0; 32];
99/// let mut result_512 = [0; 64];
100///
101/// md6::hash(256, &[], &mut result_256).unwrap();
102/// md6::hash(512, &[], &mut result_512).unwrap();
103///
104/// assert_eq!(Vec::from_iter(result_256.iter().map(|&i| i)),
105///            vec![0xBC, 0xA3, 0x8B, 0x24, 0xA8, 0x04, 0xAA, 0x37,
106///                 0xD8, 0x21, 0xD3, 0x1A, 0xF0, 0x0F, 0x55, 0x98,
107///                 0x23, 0x01, 0x22, 0xC5, 0xBB, 0xFC, 0x4C, 0x4A,
108///                 0xD5, 0xED, 0x40, 0xE4, 0x25, 0x8F, 0x04, 0xCA]);
109/// assert_eq!(Vec::from_iter(result_512.iter().map(|&i| i)),
110///            vec![0x6B, 0x7F, 0x33, 0x82, 0x1A, 0x2C, 0x06, 0x0E,
111///                 0xCD, 0xD8, 0x1A, 0xEF, 0xDD, 0xEA, 0x2F, 0xD3,
112///                 0xC4, 0x72, 0x02, 0x70, 0xE1, 0x86, 0x54, 0xF4,
113///                 0xCB, 0x08, 0xEC, 0xE4, 0x9C, 0xCB, 0x46, 0x9F,
114///                 0x8B, 0xEE, 0xEE, 0x7C, 0x83, 0x12, 0x06, 0xBD,
115///                 0x57, 0x7F, 0x9F, 0x26, 0x30, 0xD9, 0x17, 0x79,
116///                 0x79, 0x20, 0x3A, 0x94, 0x89, 0xE4, 0x7E, 0x04,
117///                 0xDF, 0x4E, 0x6D, 0xEA, 0xA0, 0xF8, 0xE0, 0xC0]);
118/// ```
119pub fn hash(hashbitlen: i32, data: &[u8], hashval: &mut [u8]) -> Result<()> {
120    match unsafe { native::MD6_Hash_Hash(hashbitlen, data.as_ptr(), data.len() as u64 * 8, hashval.as_mut_ptr()) } {
121        0 => Ok(()),
122        e => Err(Md6Error::from(e)),
123    }
124}
125
126/// Hashing state for multiple data sets.
127///
128/// # Example
129///
130/// Hashing a string split into multiple chunks.
131///
132/// ```
133/// # use md6::Md6;
134/// # use std::iter::FromIterator;
135/// let mut state = Md6::new(256).unwrap();
136///
137/// state.update(b"Abolish ");
138/// state.update(b"the ");
139/// state.update(b"bourgeoisie");
140/// state.update(b"!");
141///
142/// let mut result = [0; 32];
143/// state.finalise(&mut result);
144/// assert_eq!(Vec::from_iter(result.iter().map(|&i| i)),
145///            vec![0x49, 0x23, 0xE7, 0xB0, 0x53, 0x32, 0x05, 0xB0,
146///                 0x25, 0xC5, 0xD4, 0xDB, 0x37, 0xB8, 0x99, 0x12,
147///                 0x16, 0x2E, 0xFD, 0xF4, 0xDA, 0xC2, 0x2C, 0xFF,
148///                 0xE6, 0x27, 0xF1, 0x11, 0xEC, 0x05, 0x2F, 0xB5]);
149/// ```
150///
151/// A `Write` implementation is also provided:
152///
153/// ```
154/// # use std::iter::FromIterator;
155/// # use md6::Md6;
156/// # use std::io;
157/// let mut state = Md6::new(256).unwrap();
158/// io::copy(&mut &b"The lazy fox jumps over the lazy dog."[..], &mut state).unwrap();
159///
160/// let mut result = [0; 32];
161/// state.finalise(&mut result);
162/// assert_eq!(Vec::from_iter(result.iter().map(|&i| i)),
163///            vec![0x06, 0x60, 0xBB, 0x89, 0x85, 0x06, 0xE4, 0xD9,
164///                 0x29, 0x8C, 0xD1, 0xB0, 0x40, 0x73, 0x49, 0x60,
165///                 0x47, 0x3E, 0x25, 0xA4, 0x9D, 0x52, 0x34, 0xBB,
166///                 0x2A, 0xCA, 0x31, 0x57, 0xD1, 0xAF, 0x27, 0xAA]);
167/// ```
168pub struct Md6 {
169    raw_state: native::FFIHashState,
170}
171
172/// Some functions in the library can fail, this enum represents all the possible ways they can.
173#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
174pub enum Md6Error {
175    /// Generic failure state
176    Fail,
177    /// `hashbitlen` passed to `Md6::new()` or `hash()` incorrect
178    BadHashbitlen,
179}
180
181
182impl Md6 {
183    /// Create a new hash state and initialise it with the given bit length.
184    ///
185    /// `hashbitlen` is the hash output length. Must be between `1` and `512`.
186    ///
187    /// Returns:
188    ///
189    ///   * `Err(Md6Error::BadHashbitlen)` if `hashbitlen` is not any of the mentioned above, or
190    ///   * `Ok(Md6)` if initialisation succeeds.
191    ///
192    /// # Examples
193    ///
194    /// Incorrect `hashbitlen`
195    ///
196    /// ```
197    /// # use md6::Md6;
198    /// assert_eq!(Md6::new(0).map(|_| ()), Err(md6::Md6Error::BadHashbitlen));
199    /// assert_eq!(Md6::new(1024).map(|_| ()), Err(md6::Md6Error::BadHashbitlen));
200    /// ```
201    ///
202    /// Creating a 512-long state
203    ///
204    /// ```
205    /// # use md6::Md6;
206    /// Md6::new(512).unwrap();
207    /// ```
208    pub fn new(hashbitlen: i32) -> Result<Md6> {
209        let mut raw_state = native::malloc_hash_state();
210
211        match unsafe { native::MD6_Hash_Init(raw_state, hashbitlen) } {
212            0 => Ok(Md6 { raw_state: raw_state }),
213            e => {
214                native::free_hash_state(&mut raw_state);
215                Err(Md6Error::from(e))
216            }
217        }
218    }
219
220    /// Append the provided data to the hash function.
221    ///
222    /// # Examples
223    ///
224    /// Hashing a part of [a short story](http://nabijaczleweli.xyz/capitalism/writing/Świat_to_kilka_takich_pokoi/)
225    ///
226    /// ```
227    /// # use md6::Md6;
228    /// # use std::iter::FromIterator;
229    /// let mut result = [0; 64];
230    ///
231    /// let mut state = Md6::new(512).unwrap();
232    /// state.update("    Serbiańcy znowu się pochlali, ale w sumie".as_bytes());
233    /// state.update("czegoż się po wschodnich słowianach spodziewać, swoją".as_bytes());
234    /// state.update("drogą. I, jak to wszystkim homo sapiensom się dzieje".as_bytes());
235    /// state.update("filozofować poczęli.".as_bytes());
236    /// state.finalise(&mut result);
237    ///
238    /// assert_eq!(Vec::from_iter(result.iter().map(|&i| i)),
239    ///            vec![0xD4, 0xAC, 0x5B, 0xDA, 0x95, 0x44, 0xCC, 0x3F,
240    ///                 0xFB, 0x59, 0x4B, 0x62, 0x84, 0xEF, 0x07, 0xDD,
241    ///                 0x59, 0xE7, 0x94, 0x2D, 0xCA, 0xCA, 0x07, 0x52,
242    ///                 0x14, 0x13, 0xE8, 0x06, 0xBD, 0x84, 0xB8, 0xC7,
243    ///                 0x8F, 0xB8, 0x03, 0x24, 0x39, 0xC8, 0x2E, 0xEC,
244    ///                 0x9F, 0x7F, 0x4F, 0xDA, 0xF8, 0x8A, 0x4B, 0x5F,
245    ///                 0x9D, 0xF8, 0xFD, 0x47, 0x0C, 0x4F, 0x2F, 0x4B,
246    ///                 0xCD, 0xDF, 0xAF, 0x13, 0xE1, 0xE1, 0x4D, 0x9D]);
247    /// ```
248    pub fn update(&mut self, data: &[u8]) {
249        unsafe {
250            native::MD6_Hash_Update(self.raw_state, data.as_ptr(), data.len() as u64 * 8);
251        }
252    }
253
254
255    /// Finish hashing and store the output result in the provided space.
256    ///
257    /// The provided space must not be smaller than the hash function's size,
258    /// if the provided space is smaller than the hash function's size, the behaviour is undefined.
259    ///
260    /// # Examples
261    ///
262    /// Storing and verifying results of all possible sizes.
263    ///
264    /// ```
265    /// # use md6::Md6;
266    /// # use std::iter::FromIterator;
267    /// let mut result_64  = [0; 8];
268    /// let mut result_128 = [0; 16];
269    /// let mut result_256 = [0; 32];
270    /// let mut result_512 = [0; 64];
271    ///
272    /// let mut state_64  = Md6::new(64) .unwrap();
273    /// let mut state_128 = Md6::new(128).unwrap();
274    /// let mut state_256 = Md6::new(256).unwrap();
275    /// let mut state_512 = Md6::new(512).unwrap();
276    ///
277    /// state_64 .update(b"The lazy fox jumps over the lazy dog.");
278    /// state_128.update(b"The lazy fox jumps over the lazy dog.");
279    /// state_256.update(b"The lazy fox jumps over the lazy dog.");
280    /// state_512.update(b"The lazy fox jumps over the lazy dog.");
281    ///
282    /// state_64 .finalise(&mut result_64);
283    /// state_128.finalise(&mut result_128);
284    /// state_256.finalise(&mut result_256);
285    /// state_512.finalise(&mut result_512);
286    ///
287    /// assert_eq!(Vec::from_iter(result_64.iter().map(|&i| i)),
288    ///            vec![0xF3, 0x50, 0x60, 0xAE, 0xD7, 0xF0, 0xB0, 0x96]);
289    /// assert_eq!(Vec::from_iter(result_128.iter().map(|&i| i)),
290    ///            vec![0x08, 0x5E, 0xA5, 0xF6, 0x6D, 0x2A, 0xC1, 0xF3,
291    ///                 0xCF, 0xC5, 0x6F, 0xA3, 0x7D, 0x1B, 0xEC, 0x9C]);
292    /// assert_eq!(Vec::from_iter(result_256.iter().map(|&i| i)),
293    ///            vec![0x06, 0x60, 0xBB, 0x89, 0x85, 0x06, 0xE4, 0xD9,
294    ///                 0x29, 0x8C, 0xD1, 0xB0, 0x40, 0x73, 0x49, 0x60,
295    ///                 0x47, 0x3E, 0x25, 0xA4, 0x9D, 0x52, 0x34, 0xBB,
296    ///                 0x2A, 0xCA, 0x31, 0x57, 0xD1, 0xAF, 0x27, 0xAA]);
297    /// assert_eq!(Vec::from_iter(result_512.iter().map(|&i| i)),
298    ///            vec![0xA5, 0xFE, 0xC7, 0x36, 0x81, 0xFA, 0x64, 0xBE,
299    ///                 0xE7, 0x2D, 0xB6, 0x05, 0x35, 0x26, 0x6C, 0x00,
300    ///                 0x6B, 0x2A, 0x49, 0x54, 0x04, 0x7E, 0x39, 0x05,
301    ///                 0xD1, 0xFE, 0xB3, 0x25, 0x21, 0x01, 0x81, 0x2D,
302    ///                 0xF2, 0x20, 0xC9, 0x09, 0xD4, 0xD7, 0xB7, 0x94,
303    ///                 0x53, 0xB4, 0x2D, 0xAD, 0x6D, 0x75, 0x52, 0xC7,
304    ///                 0x82, 0xE8, 0x4E, 0xFC, 0x3C, 0x34, 0x5B, 0x0C,
305    ///                 0xFF, 0x72, 0x1B, 0x56, 0x73, 0x05, 0x6B, 0x75]);
306    /// ```
307    pub fn finalise(&mut self, hashval: &mut [u8]) {
308        unsafe {
309            native::MD6_Hash_Final(self.raw_state, hashval.as_mut_ptr());
310        }
311    }
312}
313
314/// The `Write` implementation updates the state with the provided data.
315///
316/// For example, to hash a file:
317///
318/// ```
319/// # use std::iter::FromIterator;
320/// # use std::fs::File;
321/// # use md6::Md6;
322/// # use std::io;
323/// let mut state = Md6::new(256).unwrap();
324/// io::copy(&mut File::open("LICENSE").unwrap(), &mut state).unwrap();
325///
326/// let mut result = [0; 32];
327/// state.finalise(&mut result);
328/// assert_eq!(Vec::from_iter(result.iter().map(|&i| i)),
329///            vec![0xB7, 0x82, 0xA1, 0xEA, 0xDE, 0xC5, 0x46, 0x3E,
330///                 0x1D, 0xCF, 0x56, 0xA2, 0xD7, 0x52, 0x23, 0x82,
331///                 0xA3, 0x02, 0xE6, 0xB6, 0x1D, 0x45, 0xA8, 0xBF,
332///                 0x95, 0x12, 0x92, 0x1E, 0xAD, 0x21, 0x3E, 0x47]);
333/// ```
334impl io::Write for Md6 {
335    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
336        self.update(buf);
337        Ok(buf.len())
338    }
339
340    fn flush(&mut self) -> io::Result<()> {
341        Ok(())
342    }
343}
344
345impl Drop for Md6 {
346    fn drop(&mut self) {
347        native::free_hash_state(&mut self.raw_state);
348    }
349}
350
351
352impl Error for Md6Error {
353    fn description(&self) -> &str {
354        match self {
355            &Md6Error::Fail => "Generic MD6 fail",
356            &Md6Error::BadHashbitlen => "Incorrect hashbitlen",
357        }
358    }
359}
360
361impl From<i32> for Md6Error {
362    /// Passing incorrect error values yields unspecified behaviour.
363    fn from(i: i32) -> Self {
364        match i {
365            0 => panic!("Not an error"),
366            1 => Md6Error::Fail,
367            2 => Md6Error::BadHashbitlen,
368            _ => panic!("Incorrect error number"),
369        }
370    }
371}
372
373impl fmt::Display for Md6Error {
374    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
375        write!(f, "{:?}", self)
376    }
377}