Skip to main content

sha/
sha1.rs

1/// `Sha1` structure interface to the SHA-1 message digest algorithm.
2///
3/// # Examples
4///
5/// The following sections are some typical examples illustrating the use of the `Sha1` structure.
6///
7/// ## Example digesting the empty message with SHA-1
8///
9/// ```rust
10/// use std::default::Default;
11/// use self::sha::sha1::Sha1;
12/// use self::sha::utils::{Digest, DigestExt};
13///
14/// assert_eq!(Sha1::default().digest("".as_bytes()).to_hex(),
15///            "da39a3ee5e6b4b0d3255bfef95601890afd80709");
16/// ```
17///
18/// ## Example digesting the message `"abc"` with SHA-1.
19///
20/// ```rust
21/// use std::default::Default;
22/// use self::sha::sha1::Sha1;
23/// use self::sha::utils::{Digest, DigestExt};
24///
25/// assert_eq!(Sha1::default().digest("abc".as_bytes()).to_hex(),
26///            "a9993e364706816aba3e25717850c26c9cd0d89d");
27/// ```
28///
29/// ## Example digesting the message with one million repetitions of `"a"` with SHA-1.
30///
31/// ```rust
32/// use std::default::Default;
33/// use self::sha::utils::ReadPad;
34/// use self::sha::sha1;
35///
36/// {
37///     let mut state: [u32; 5] = sha1::consts::H;
38///     let block: [u8; 64] = [0x61; 64]; // "a"
39///     
40///     // 15625 blocks of 64 bytes each is 1 million bytes.
41///     for _ in 0 .. 15625 - 1 {
42///         sha1::ops::digest_block(&mut state, &block[..]);
43///     }
44///
45///     // incremental digest requires that you do the padding
46///     let mut pad_blocks: Vec<u8> = block.to_vec();
47///     sha1::ops::pad(1000000).read_pad(&mut pad_blocks);
48///     for pad_block in (&pad_blocks[..]).chunks(64) {
49///         sha1::ops::digest_block(&mut state, &pad_block[..]);
50///     }
51///
52///     // serialize the digest state
53///     let hash: String = format!("{:08x}{:08x}{:08x}{:08x}{:08x}", 
54///                                state[0], state[1], state[2], 
55///                                state[3], state[4]);
56///
57///     assert_eq!(hash,
58///                "34aa973cd4c4daa4f61eeb2bdbad27316534016f");
59/// }
60/// ```
61#[derive(Clone)]
62pub struct Sha1(pub [u32; 5], Vec<u8>);
63
64mod impls {
65    use std::borrow::Borrow;
66    use std::default::Default;
67    use std::hash::Hasher;
68    use std::io::prelude::*;
69    use std::io;
70    use bswap::beu32;
71    use super::Sha1;
72    use utils::{Reset,
73                Digest,
74                DigestExt,
75                ReadPadBlocksExt};
76
77    impl Default for Sha1 {
78
79        /// Construct a default `Sha1` object.
80        fn default() -> Sha1 {
81            Sha1(super::consts::H, Vec::new())
82        }
83    }
84
85    impl Reset for Sha1 {
86
87        /// (Step 0) Reset the state
88        fn reset(&mut self) {
89            self.0 = super::consts::H;
90            self.1.clear();
91        }
92    }
93
94    impl Write for Sha1 {
95
96        /// (Step 1) Write to buffer
97        fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
98            Write::write(&mut self.1, buf)
99        }
100
101        /// Digest buffer
102        fn flush(&mut self) -> io::Result<()> {
103            let mut state = self.0;
104            let ref buf = self.1;
105
106            for block in buf.pad_blocks(64, super::ops::pad) {
107                super::ops::digest_block(&mut state, block.borrow());
108            }
109
110            self.0 = state;
111            Ok(())
112        }
113    }
114
115    impl Read for Sha1 {
116
117        /// (Step 4) Read state as big-endian
118        ///
119        /// The buffer length must be a multiple of 4.
120        fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
121            let state_buf = &self.0[..buf.len()/4];
122            beu32::encode_slice(buf, state_buf);
123            Ok(buf.len())
124        }
125    }
126
127    impl Hasher for Sha1 {
128
129        /// Get the first 8 bytes of the state
130        fn finish(&self) -> u64 {
131            let mut h = self.clone();
132            h.flush().unwrap();
133            let state = h.0;
134
135            ((state[0] as u64) << 32u64) |
136             (state[1] as u64)
137        }
138
139        /// Write to buffer
140        fn write(&mut self, buf: &[u8]) {
141            Write::write(self, buf).unwrap();
142        }
143    }
144
145    impl Digest for Sha1 {}
146
147    impl DigestExt for Sha1 {
148            fn default_len() -> usize {
149            return 20;
150        }
151    }
152}
153
154/// TODO
155//#[unstable(feature="default", reason="TODO")]
156pub mod consts {
157
158    /// TODO
159    pub const H: [u32; 5] = [
160        0x67452301,
161        0xefcdab89,
162        0x98badcfe,
163        0x10325476,
164        0xc3d2e1f0];
165
166    /// TODO
167    pub const K: [u32; 4] = [
168        0x5a827999,
169        0x6ed9eba1,
170        0x8f1bbcdc,
171        0xca62c1d6];
172}
173
174
175/// TODO: docs
176pub mod ops {
177    use bswap::{beu32, beu64};
178    use utils::StdPad;
179
180    macro_rules! rotate_left {
181        ($a:expr, $b:expr) => (($a << $b) ^ ($a >> (32 - $b)))
182    }
183    macro_rules! bool3ary_150 {
184        ($a:expr, $b:expr, $c:expr) => ($a ^ $b ^ $c)
185    } // 3, xor, parity, MD5H, SHA1F1, SHA1F3, --half, --sym, SHA1P
186    macro_rules! bool3ary_202 {
187        ($a:expr, $b:expr, $c:expr) => ($c ^ ($a & ($b ^ $c)))
188    } // 3, MD5F, SHA1F0, --half, SHA1C
189    macro_rules! bool3ary_232 {
190        ($a:expr, $b:expr, $c:expr) => (($a & $b) ^ ($a & $c) ^ ($b & $c))
191    } // 3, majority, SHA1F2, --half, SHA1M
192
193    macro_rules! round_func {
194        ($a:expr, $b:expr, $c:expr, $i:expr) => {
195            match $i {
196                0 => bool3ary_202!($a, $b, $c),
197                1 => bool3ary_150!($a, $b, $c),
198                2 => bool3ary_232!($a, $b, $c),
199                3 => bool3ary_150!($a, $b, $c),
200                _ => panic!("unknown icosaround index")
201            }
202        }
203    }
204
205    macro_rules! sha1_expand_round {
206        ($work:expr, $t:expr) => {
207            {
208                let temp = $work[($t + 4 + 0) % 20]
209                    ^ $work[($t + 4 + 2) % 20]
210                    ^ $work[($t + 4 + 8) % 20]
211                    ^ $work[($t + 4 + 13) % 20];
212
213                $work[($t + 0) % 20] = rotate_left!(temp, 1);
214            }
215        }
216    }
217
218    macro_rules! sha1_digest_round {
219        ($a:ident, $b:ident, $c:ident, $d:ident,
220         $e:ident, $w:expr, $i:expr) => {
221            {
222                use super::consts::K;
223
224                $e = $e
225                    .wrapping_add(K[$i])
226                    .wrapping_add($w)
227                    .wrapping_add(rotate_left!($a, 5))
228                    .wrapping_add(round_func!($b, $c, $d, $i));
229
230                $b = rotate_left!($b, 30);
231            }
232        }
233    }
234
235    /// This function can be easily implemented with Intel SHA intruction set extensions.
236    ///
237    /// ```ignore
238    /// {
239    ///     sha1msg2(sha1msg1(work[0], work[1]) ^ work[2], work[3])
240    /// }
241    /// ```
242    #[inline]
243    pub fn expand_round_x4(w: &mut [u32; 20], t: usize) {
244        sha1_expand_round!(w, t);
245        sha1_expand_round!(w, t + 1);
246        sha1_expand_round!(w, t + 2);
247        sha1_expand_round!(w, t + 3);
248    }
249
250    /// This function can be easily implemented with Intel SHA intruction set extensions.
251    ///
252    /// ```ignore
253    /// {
254    ///     let abcd = u32x4(a, b, c, d);
255    ///     let e000 = u32x4(e, 0, 0, 0);
256    ///
257    ///     abcd = sha1rnds4(abcd, e000 + work, i);
258    ///
259    ///     e = a.rotate_left(30);
260    ///     a = abcd.0;
261    ///     b = abcd.1;
262    ///     c = abcd.2;
263    ///     d = abcd.3;
264    /// }
265    /// ```
266    #[inline]
267    pub fn digest_round_x4(state: &mut [u32; 5], w: [u32; 4], i: usize) {
268        let mut a = state[0];
269        let mut b = state[1];
270        let mut c = state[2];
271        let mut d = state[3];
272        let mut e = state[4];
273        sha1_digest_round!(a, b, c, d, e, w[0], i);
274        sha1_digest_round!(e, a, b, c, d, w[1], i);
275        sha1_digest_round!(d, e, a, b, c, w[2], i);
276        sha1_digest_round!(c, d, e, a, b, w[3], i);
277        *state = [b, c, d, e, a];
278    }
279
280    #[inline]
281    pub fn expand_round_x20(w: &mut [u32; 20]) {
282        expand_round_x4(w, 0);
283        expand_round_x4(w, 4);
284        expand_round_x4(w, 8);
285        expand_round_x4(w, 12);
286        expand_round_x4(w, 16);
287    }
288
289    #[inline]
290    pub fn digest_round_x20(state: &mut [u32; 5], w: [u32; 20], i: usize) {
291        macro_rules! as_simd {
292            ($x:expr) => {
293                {
294                    let (y, _): (&[u32; 4], usize) =
295                        unsafe {::std::mem::transmute($x)}; *y
296                }
297            }
298        }
299
300        digest_round_x4(state, as_simd!(&w[0..4]), i);
301        digest_round_x4(state, as_simd!(&w[4..8]), i);
302        digest_round_x4(state, as_simd!(&w[8..12]), i);
303        digest_round_x4(state, as_simd!(&w[12..16]), i);
304        digest_round_x4(state, as_simd!(&w[16..20]), i);
305    }
306
307    /// TODO
308    pub fn digest_block(state: &mut [u32; 5], buf: &[u8]) {
309        let state2 = *state;
310        let mut w: [u32; 20] = [0; 20];
311
312        beu32::decode_slice(&mut w[..16], buf);
313        expand_round_x4(&mut w, 16);
314        digest_round_x20(state, w, 0);
315        expand_round_x20(&mut w);
316        digest_round_x20(state, w, 1);
317        expand_round_x20(&mut w);
318        digest_round_x20(state, w, 2);
319        expand_round_x20(&mut w);
320        digest_round_x20(state, w, 3);
321
322        for i in 0..5 {
323            state[i] = state[i]
324                .wrapping_add(state2[i]);
325        }
326    }
327
328    /// TODO
329    pub fn digest(buf: &[u8]) -> [u32; 5] {
330        use std::default::Default;
331        use utils::Digest;
332
333        super::Sha1::default().digest(buf).0
334    }
335
336    pub fn pad(len: usize) -> StdPad {
337        let mut suffix = vec![0u8; 8];
338        beu64::encode(&mut suffix[..], 8*len as u64);
339        StdPad::new(suffix, 64)
340    }
341}
342
343#[cfg(test)]
344mod tests {
345    use std::default::Default;
346    //use std::io::prelude::*;
347    use super::Sha1;
348    use utils::{Digest, DigestExt};
349
350    //
351    // Helper functions
352    //
353
354    //fn digest_block(state: &mut [u32; 5], buf: &[u8]) {
355    //    super::ops::digest_block(state, buf);
356    //}
357
358    fn digest(buf: &[u8]) -> Sha1 {
359        let mut h: Sha1 = Default::default();
360        h.digest(buf);
361        h
362    }
363
364    fn digest_to_bytes(buf: &[u8]) -> Vec<u8> {
365        digest(buf).to_bytes()
366    }
367
368    fn digest_to_hex(msg: &str) -> String {
369        digest(&msg.as_bytes()).to_hex()
370    }
371
372    //
373    // Tests for `hash`
374    //
375
376    #[test]
377    fn test_sha1_empty_hash() {
378        use std::hash::{Hash, Hasher};
379
380        let msg: &[u8] = "".as_bytes();
381        let mut h: Sha1 = Default::default();
382        <u8 as Hash>::hash_slice(msg, &mut h);
383        let digest: u64 = h.finish();
384        assert_eq!(0xda39a3ee5e6b4b0du64, digest);
385    }
386
387    #[test]
388    fn test_sha1_hello_hash() {
389        use std::hash::{Hash, Hasher};
390
391        let msg: &[u8] = "hello world".as_bytes();
392        let mut h: Sha1 = Default::default();
393        <u8 as Hash>::hash_slice(msg, &mut h);
394        let digest: u64 = h.finish();
395        assert_eq!(0x2aae6c35c94fcfb4u64, digest);
396    }
397
398    //
399    // Tests for `digest_to_hex`
400    //
401
402    #[test]
403    fn test_sha1_empty() {
404        assert_eq!("da39a3ee5e6b4b0d3255bfef95601890afd80709",
405                   digest_to_hex(""));
406    }
407
408    #[test]
409    fn test_sha1_hello() {
410        assert_eq!("2aae6c35c94fcfb415dbe95f408b9ce91ee846ed",
411                   digest_to_hex("hello world"));
412        assert_eq!("430ce34d020724ed75a196dfc2ad67c77772d169",
413                   digest_to_hex("hello world!"));
414        assert_eq!("22c219648f00c61e5b3b1bd81ffa8e7767e2e3c5",
415                   digest_to_hex("hello World"));
416        assert_eq!("788245b4dad73c1e5a630c126c484c7a2464f280",
417                   digest_to_hex("hello World!"));
418        assert_eq!("7b502c3a1f48c8609ae212cdfb639dee39673f5e",
419                   digest_to_hex("Hello world"));
420        assert_eq!("d3486ae9136e7856bc42212385ea797094475802",
421                   digest_to_hex("Hello world!"));
422        assert_eq!("0a4d55a8d778e5022fab701977c5d840bbc486d0",
423                   digest_to_hex("Hello World"));
424        assert_eq!("2ef7bde608ce5404e97d5f042f95f89f1c232871",
425                   digest_to_hex("Hello World!"));
426        assert_eq!("b7e23ec29af22b0b4e41da31e868d57226121c84",
427                   digest_to_hex("hello, world"));
428        assert_eq!("1f09d30c707d53f3d16c530dd73d70a6ce7596a9",
429                   digest_to_hex("hello, world!"));
430        assert_eq!("ca3c58516ddef44b25693df5a915206e1bd094da",
431                   digest_to_hex("hello, World"));
432        assert_eq!("dd0588c172986c32636ffdd8cc690de7b41bf253",
433                   digest_to_hex("hello, World!"));
434        assert_eq!("e02aa1b106d5c7c6a98def2b13005d5b84fd8dc8",
435                   digest_to_hex("Hello, world"));
436        assert_eq!("943a702d06f34599aee1f8da8ef9f7296031d699",
437                   digest_to_hex("Hello, world!"));
438        assert_eq!("907d14fb3af2b0d4f18c2d46abe8aedce17367bd",
439                   digest_to_hex("Hello, World"));
440        assert_eq!("0a0a9f2a6772942557ab5355d76af442f8f65e01",
441                   digest_to_hex("Hello, World!"));
442    }
443
444    #[test]
445    fn test_sha1_multi() {
446        let s = "GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>";
447        assert_eq!("a31e8cb8a139d146a0070fa13795d6766acaccd4", digest_to_hex(s));
448    }
449
450
451    //#[bench]
452    //fn bench_sha1_hello(b: & mut Bencher) {
453    //    let s = "hello world";
454    //
455    //    b.iter(|| digest_to_hex(s));
456    //    b.bytes = s.len() as u64;
457    //}
458    //
459    //#[bench]
460    //fn bench_sha1_multi(b: & mut Bencher) {
461    //    let s = "GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>";
462    //
463    //    b.iter(|| digest_to_hex(s));
464    //    b.bytes = s.len() as u64;
465    //}
466
467    //#[bench]
468    //pub fn block_64(bh: & mut Bencher) {
469    //    let mut state = [0u8; 20];
470    //    let bytes = [1u8; 64];
471    //    bh.iter( || {
472    //            digest_block(&mut state, &bytes[..]);
473    //        });
474    //    bh.bytes = bytes.len() as u64;
475    //}
476
477    //
478    // Benchmarks for `digest`
479    //
480
481    //#[bench]
482    //fn bench_sha1_10(b: & mut Bencher) {
483    //    let buf = [0x20u8; 10];
484    //    b.iter( || { digest(&buf[..]); });
485    //    b.bytes = buf.len() as u64;
486    //}
487    //#[bench]
488    //fn bench_sha1_1k(b: & mut Bencher) {
489    //    let buf = [0x20u8; 1024];
490    //    b.iter( || { digest(&buf[..]); });
491    //    b.bytes = buf.len() as u64;
492    //}
493    //#[bench]
494    //fn bench_sha1_64k(b: & mut Bencher) {
495    //    let buf = [0x20u8; 65536];
496    //    b.iter( || { digest(&buf[..]); });
497    //    b.bytes = buf.len() as u64;
498    //}
499
500    //
501    // Benchmarks for `digest_to_bytes`
502    //
503
504    //#[bench]
505    //fn bench_sha1_to_bytes_10(b: & mut Bencher) {
506    //    let buf = [0x20u8; 10];
507    //    b.iter( || { digest_to_bytes(&buf[..]); });
508    //    b.bytes = buf.len() as u64;
509    //}
510    //#[bench]
511    //fn bench_sha1_to_bytes_1k(b: & mut Bencher) {
512    //    let buf = [0x20u8; 1024];
513    //    b.iter( || { digest_to_bytes(&buf[..]); });
514    //    b.bytes = buf.len() as u64;
515    //}
516    //#[bench]
517    //fn bench_sha1_to_bytes_64k(b: & mut Bencher) {
518    //    let buf = [0x20u8; 65536];
519    //    b.iter( || { digest_to_bytes(&buf[..]); });
520    //    b.bytes = buf.len() as u64;
521    //}
522
523    //
524    // Benchmarks for `digest_to_hex`
525    //
526
527    //#[bench]
528    //fn bench_sha1_to_hex_10(b: & mut Bencher) {
529    //    let buf = [0x20u8; 10];
530    //    let msg = ::std::str::from_utf8(&buf[..]).unwrap();
531    //    b.iter( || { digest_to_hex(msg); });
532    //    b.bytes = msg.len() as u64;
533    //}
534    //#[bench]
535    //fn bench_sha1_to_hex_1k(b: & mut Bencher) {
536    //    let buf = [0x20u8; 1024];
537    //    let msg = ::std::str::from_utf8(&buf[..]).unwrap();
538    //    b.iter( || { digest_to_hex(msg); });
539    //    b.bytes = msg.len() as u64;
540    //}
541    //#[bench]
542    //fn bench_sha1_to_hex_64k(b: & mut Bencher) {
543    //    let buf = [0x20u8; 65536];
544    //    let msg = ::std::str::from_utf8(&buf[..]).unwrap();
545    //    b.iter( || { digest_to_hex(msg); });
546    //    b.bytes = msg.len() as u64;
547    //}
548}