rbtables/
lib.rs

1extern crate crossbeam;
2extern crate num_cpus;
3#[macro_use]
4extern crate lazy_static;
5
6// Silences warnings about unused macros
7lazy_static!{}
8
9pub mod prelude;
10
11#[cfg(test)]
12mod tests {
13    extern crate md5;
14    extern crate rand;
15
16    use prelude::{Hasher, Reducer, RainbowTable};
17    use self::rand::{thread_rng, Rng};
18
19    // This hasher performs an MD5 digest
20    struct MD5Hasher;
21    impl Hasher for MD5Hasher {
22        fn digest(&self, plaintext : &str) -> String {
23            format!("{:x}", md5::compute(plaintext.as_bytes()))
24        }
25    }
26
27    // This reducer simply takes the first n characters of a hash 
28    struct SubstringReducer {
29        n: usize
30    }
31    impl Reducer for SubstringReducer {
32        fn reduce(&self, hash : &str) -> String {
33            String::from(&hash[..self.n])
34        }
35    }
36
37    lazy_static! {
38        static ref TABLE : RainbowTable<MD5Hasher, SubstringReducer> = {
39            // Build a list of substring reducers, each of which will be applied in succession 
40            let mut rfs : Vec<SubstringReducer> = Vec::new();
41            for i in 6..27 {
42                rfs.push(SubstringReducer { n : i });
43            }
44
45            // Create the table using an MD5 hasher and the list of substring reducers
46            let mut table : RainbowTable<MD5Hasher, SubstringReducer> = RainbowTable::new(MD5Hasher, rfs);
47
48            // Add numbers in [0, 999] as test seeds 
49            for i in 0..1000 {
50                table.add_seed(format!("{}", i));
51            }
52
53            table
54        };
55    }
56
57    #[test]
58    fn test_rainbow_table_find_seeds() {
59        // Test that the rainbow table can find the hashes of the seed values
60        for i in 0..1000 {
61            let seed = format!("{}", i);
62            let seed_hash = format!("{:x}", md5::compute(seed.as_bytes()));
63            assert_eq!(Some(seed), TABLE.find_plaintext(&seed_hash));
64        }
65    }
66
67    #[test]
68    fn test_rainbow_table_find_random() {
69        // Build out a list of reducers used in the actual table
70        let mut rfs : Vec<SubstringReducer> = Vec::new();
71        let hf = MD5Hasher;
72        for i in 6..27 {
73            rfs.push(SubstringReducer { n : i });
74        }
75
76        // Test that the rainbow table can find hashes that appear randomly in the table
77        let mut rng = thread_rng();
78        for _ in 0..1000 {
79            let mut value = format!("{}", rng.gen_range(0, 1000));
80            let reductions = rng.gen_range(1, rfs.len());
81            for i in 0..reductions {
82                value = rfs[i].reduce(&hf.digest(&value[..])[..]); 
83            }
84            let mut hash = hf.digest(&value[..]);
85            assert_eq!(Some(value), TABLE.find_plaintext(&hash));
86        }
87    }
88
89    #[test]
90    fn test_rainbow_table_find_none() {
91        // Test that the table will return None when presented with a hash not in the table 
92        assert_eq!(None, TABLE.find_plaintext("8a1fb399dcf220db935995abce6a1532"));
93    }
94}
95