1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#[macro_use]
mod macros;

pub mod md2;
pub mod md4;

pub trait HashFunction {
    /// Set the input bytes of the HashFunction
    ///
    /// Also effectively performs a reset of the inner state,
    /// this means retrieving a previously calculated hash is no
    /// longer possible.
    ///
    /// # Arguments
    /// * `input` - The input bytes to hash
    fn set_input(&mut self, input: &[u8]);

    /// Convenience method to set a &str as input
    ///
    /// # Arguments
    /// * `input_str` - The input &str to hash
    fn set_input_str(&mut self, input_str: &str) {
        self.set_input(input_str.as_bytes());
    }

    /// Performs all necessary hashing operations
    ///
    /// After this method returns the hash calculations
    /// are done and the output can be retrieved.
    fn hash(&mut self);

    /// Retrieve the output of the applied HashFunction
    ///
    /// Can only be called after hash() returned successfully, but
    /// multiple times.
    ///
    /// # Arguments
    /// * `output` - The vector to write the output to. Must be
    ///     big enough to store at least get_output_length bytes
    fn get_output(&mut self, output: &mut [u8]);

    /// Convenience method to retrieve the output of the HashFunction
    /// as the commonly used hex-String
    ///
    /// Can also be called multiple times.
    ///
    /// # Returns
    /// * The resulting hex-String
    //FIXME: figure out how to properly document return values
    fn get_output_str(&mut self) -> String {
        use rustc_serialize::hex::ToHex;
        use std::vec::Vec;

        let mut output: Vec<u8> = (0..self.get_output_length()).map(|_| 0).collect();
        self.get_output(&mut output[..]);
        output.to_hex()
    }

    /// Returns the blocksize of the HashFunction used in bytes
    ///
    /// # Returns
    /// * The used blocksize
    fn get_blocksize(&self) -> u32;

    /// Returns the length of the result vector in bits as commonly used
    /// in hash specifications
    ///
    /// # Returns
    /// * The length if the output vector in bits
    fn get_output_length_in_bits(&self) -> u32;

    /// Convenience method to calculate the required size of a output vector in bytes
    ///
    /// # Returns
    /// * The length of the output vector in bytes
    fn get_output_length(&self) -> usize {
        ((self.get_output_length_in_bits() + 7) / 8) as usize
    }
}

#[cfg(test)]
mod test {
    use hashes::HashFunction;

    pub struct HashTestCase {
        pub input:      &'static str,
        pub output:     Vec<u8>,
        pub output_str: &'static str
    }

    pub fn perform_hash_test(hash: &mut HashFunction, test: &HashTestCase) {
        println!("Testing hash against:\t \"{:2}\"", test.input);
        hash.set_input_str(test.input);
        hash.hash();

        let mut result = Vec::from_elem(hash.get_output_length(), 0u8);
        hash.get_output(result.as_mut_slice());
        let result_str = hash.get_output_str();

        print!("result: \t\t");
        for r in result.iter() {
            print!("0x{:x} ", *r)
        }
        println!("");
        print!("(expected) output:\t");
        for o in test.output.iter() {
            print!("0x{:x} ", *o)
        }
        println!("");
        println!("result_str:\t\t{}", result_str);
        println!("(expected) output_str:\t{}", test.output_str);
        println!("");

        assert!(result == test.output);
        assert!(result_str.as_slice() == test.output_str);
    }
}