crypto/
sha1.rs

1// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution and at
3// http://rust-lang.org/COPYRIGHT.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
11/*!
12An implementation of the SHA-1 cryptographic hash algorithm.
13
14To use this module, first create a `Sha1` object using the `Sha1` constructor,
15then feed it an input message using the `input` or `input_str` methods,
16which may be called any number of times; they will buffer the input until
17there is enough to call the block algorithm.
18
19After the entire input has been fed to the hash read the result using
20the `result` or `result_str` methods. The first will return bytes, and
21the second will return a `String` object of the same bytes represented
22in hexadecimal form.
23
24The `Sha1` object may be reused to create multiple hashes by calling
25the `reset()` method. These traits are implemented by all hash digest
26algorithms that implement the `Digest` trait. An example of use is:
27
28```rust
29use self::crypto::digest::Digest;
30use self::crypto::sha1::Sha1;
31
32// create a Sha1 object
33let mut hasher = Sha1::new();
34
35// write input message
36hasher.input_str("hello world");
37
38// read hash digest
39let hex = hasher.result_str();
40
41assert_eq!(hex, "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed");
42```
43
44# Mathematics
45
46The mathematics of the SHA-1 algorithm are quite interesting. In its
47definition, The SHA-1 algorithm uses:
48
49* 1 binary operation on bit-arrays:
50  * "exclusive or" (XOR)
51* 2 binary operations on integers:
52  * "addition" (ADD)
53  * "rotate left" (ROL)
54* 3 ternary operations on bit-arrays:
55  * "choose" (CH)
56  * "parity" (PAR)
57  * "majority" (MAJ)
58
59Some of these functions are commonly found in all hash digest
60algorithms, but some, like "parity" is only found in SHA-1.
61 */
62
63use digest::Digest;
64use cryptoutil::{write_u32_be, read_u32v_be, add_bytes_to_bits, FixedBuffer, FixedBuffer64, StandardPadding};
65use simd::u32x4;
66
67const STATE_LEN: usize = 5;
68const BLOCK_LEN: usize = 16;
69
70const K0: u32 = 0x5A827999u32;
71const K1: u32 = 0x6ED9EBA1u32;
72const K2: u32 = 0x8F1BBCDCu32;
73const K3: u32 = 0xCA62C1D6u32;
74
75/// Not an intrinsic, but gets the first element of a vector.
76#[inline]
77pub fn sha1_first(w0: u32x4) -> u32 {
78    w0.0
79}
80
81/// Not an intrinsic, but adds a word to the first element of a vector.
82#[inline]
83pub fn sha1_first_add(e: u32, w0: u32x4) -> u32x4 {
84    let u32x4(a, b, c, d) = w0;
85    u32x4(e.wrapping_add(a), b, c, d)
86}
87
88/// Emulates `llvm.x86.sha1msg1` intrinsic.
89fn sha1msg1(a: u32x4, b: u32x4) -> u32x4 {
90    let u32x4(_, _, w2, w3) = a;
91    let u32x4(w4, w5, _, _) = b;
92    a ^ u32x4(w2, w3, w4, w5)
93}
94
95/// Emulates `llvm.x86.sha1msg2` intrinsic.
96fn sha1msg2(a: u32x4, b: u32x4) -> u32x4 {
97    let u32x4(x0, x1, x2, x3) = a;
98    let u32x4(_, w13, w14, w15) = b;
99
100    let w16 = (x0 ^ w13).rotate_left(1);
101    let w17 = (x1 ^ w14).rotate_left(1);
102    let w18 = (x2 ^ w15).rotate_left(1);
103    let w19 = (x3 ^ w16).rotate_left(1);
104
105    u32x4(w16, w17, w18, w19)
106}
107
108/// Performs 4 rounds of the message schedule update.
109pub fn sha1_schedule_x4(v0: u32x4, v1: u32x4, v2: u32x4, v3: u32x4) -> u32x4 {
110    sha1msg2(sha1msg1(v0, v1) ^ v2, v3)
111}
112
113/// Emulates `llvm.x86.sha1nexte` intrinsic.
114#[inline]
115pub fn sha1_first_half(abcd: u32x4, msg: u32x4) -> u32x4 {
116    sha1_first_add(sha1_first(abcd).rotate_left(30), msg)
117}
118
119/// Emulates `llvm.x86.sha1rnds4` intrinsic.
120/// Performs 4 rounds of the message block digest.
121pub fn sha1_digest_round_x4(abcd: u32x4, work: u32x4, i: i8) -> u32x4 {
122    const K0V: u32x4 = u32x4(K0, K0, K0, K0);
123    const K1V: u32x4 = u32x4(K1, K1, K1, K1);
124    const K2V: u32x4 = u32x4(K2, K2, K2, K2);
125    const K3V: u32x4 = u32x4(K3, K3, K3, K3);
126
127    match i {
128        0 => sha1rnds4c(abcd, work + K0V),
129        1 => sha1rnds4p(abcd, work + K1V),
130        2 => sha1rnds4m(abcd, work + K2V),
131        3 => sha1rnds4p(abcd, work + K3V),
132        _ => panic!("unknown icosaround index")
133    }
134}
135
136/// Not an intrinsic, but helps emulate `llvm.x86.sha1rnds4` intrinsic.
137fn sha1rnds4c(abcd: u32x4, msg: u32x4) -> u32x4 {
138    let u32x4(mut a, mut b, mut c, mut d) = abcd;
139    let u32x4(t, u, v, w) = msg;
140    let mut e = 0u32;
141
142    macro_rules! bool3ary_202 {
143        ($a:expr, $b:expr, $c:expr) => (($c ^ ($a & ($b ^ $c))))
144    } // Choose, MD5F, SHA1C
145
146    e = e.wrapping_add(a.rotate_left(5)).wrapping_add(bool3ary_202!(b, c, d)).wrapping_add(t);
147    b = b.rotate_left(30);
148
149    d = d.wrapping_add(e.rotate_left(5)).wrapping_add(bool3ary_202!(a, b, c)).wrapping_add(u);
150    a = a.rotate_left(30);
151
152    c = c.wrapping_add(d.rotate_left(5)).wrapping_add(bool3ary_202!(e, a, b)).wrapping_add(v);
153    e = e.rotate_left(30);
154
155    b = b.wrapping_add(c.rotate_left(5)).wrapping_add(bool3ary_202!(d, e, a)).wrapping_add(w);
156    d = d.rotate_left(30);
157
158    u32x4(b, c, d, e)
159}
160
161/// Not an intrinsic, but helps emulate `llvm.x86.sha1rnds4` intrinsic.
162fn sha1rnds4p(abcd: u32x4, msg: u32x4) -> u32x4 {
163    let u32x4(mut a, mut b, mut c, mut d) = abcd;
164    let u32x4(t, u, v, w) = msg;
165    let mut e = 0u32;
166
167    macro_rules! bool3ary_150 {
168        ($a:expr, $b:expr, $c:expr) => (($a ^ $b ^ $c))
169    } // Parity, XOR, MD5H, SHA1P
170
171    e = e.wrapping_add(a.rotate_left(5)).wrapping_add(bool3ary_150!(b, c, d)).wrapping_add(t);
172    b = b.rotate_left(30);
173
174    d = d.wrapping_add(e.rotate_left(5)).wrapping_add(bool3ary_150!(a, b, c)).wrapping_add(u);
175    a = a.rotate_left(30);
176
177    c = c.wrapping_add(d.rotate_left(5)).wrapping_add(bool3ary_150!(e, a, b)).wrapping_add(v);
178    e = e.rotate_left(30);
179
180    b = b.wrapping_add(c.rotate_left(5)).wrapping_add(bool3ary_150!(d, e, a)).wrapping_add(w);
181    d = d.rotate_left(30);
182
183    u32x4(b, c, d, e)
184}
185
186/// Not an intrinsic, but helps emulate `llvm.x86.sha1rnds4` intrinsic.
187fn sha1rnds4m(abcd: u32x4, msg: u32x4) -> u32x4 {
188    let u32x4(mut a, mut b, mut c, mut d) = abcd;
189    let u32x4(t, u, v, w) = msg;
190    let mut e = 0u32;
191
192    macro_rules! bool3ary_232 {
193        ($a:expr, $b:expr, $c:expr) => (($a & $b) ^ ($a & $c) ^ ($b & $c))
194    } // Majority, SHA1M
195
196    e = e.wrapping_add(a.rotate_left(5)).wrapping_add(bool3ary_232!(b, c, d)).wrapping_add(t);
197    b = b.rotate_left(30);
198
199    d = d.wrapping_add(e.rotate_left(5)).wrapping_add(bool3ary_232!(a, b, c)).wrapping_add(u);
200    a = a.rotate_left(30);
201
202    c = c.wrapping_add(d.rotate_left(5)).wrapping_add(bool3ary_232!(e, a, b)).wrapping_add(v);
203    e = e.rotate_left(30);
204
205    b = b.wrapping_add(c.rotate_left(5)).wrapping_add(bool3ary_232!(d, e, a)).wrapping_add(w);
206    d = d.rotate_left(30);
207
208    u32x4(b, c, d, e)
209}
210
211/// Process a block with the SHA-1 algorithm.
212pub fn sha1_digest_block_u32(state: &mut [u32; 5], block: &[u32; 16]) {
213
214    macro_rules! schedule {
215        ($v0:expr, $v1:expr, $v2:expr, $v3:expr) => (
216            sha1msg2(sha1msg1($v0, $v1) ^ $v2, $v3)
217        )
218    }
219
220    macro_rules! rounds4 {
221        ($h0:ident, $h1:ident, $wk:expr, $i:expr) => (
222            sha1_digest_round_x4($h0, sha1_first_half($h1, $wk), $i)
223        )
224    }
225
226    // Rounds 0..20
227    let mut h0 = u32x4(state[0],
228                       state[1],
229                       state[2],
230                       state[3]);
231    let mut w0 = u32x4(block[0],
232                       block[1],
233                       block[2],
234                       block[3]);
235    let mut h1 = sha1_digest_round_x4(h0, sha1_first_add(state[4], w0), 0);
236    let mut w1 = u32x4(block[4],
237                       block[5],
238                       block[6],
239                       block[7]);
240    h0 = rounds4!(h1, h0, w1, 0);
241    let mut w2 = u32x4(block[8],
242                       block[9],
243                       block[10],
244                       block[11]);
245    h1 = rounds4!(h0, h1, w2, 0);
246    let mut w3 = u32x4(block[12],
247                       block[13],
248                       block[14],
249                       block[15]);
250    h0 = rounds4!(h1, h0, w3, 0);
251    let mut w4 = schedule!(w0, w1, w2, w3);
252    h1 = rounds4!(h0, h1, w4, 0);
253
254    // Rounds 20..40
255    w0 = schedule!(w1, w2, w3, w4);
256    h0 = rounds4!(h1, h0, w0, 1);
257    w1 = schedule!(w2, w3, w4, w0);
258    h1 = rounds4!(h0, h1, w1, 1);
259    w2 = schedule!(w3, w4, w0, w1);
260    h0 = rounds4!(h1, h0, w2, 1);
261    w3 = schedule!(w4, w0, w1, w2);
262    h1 = rounds4!(h0, h1, w3, 1);
263    w4 = schedule!(w0, w1, w2, w3);
264    h0 = rounds4!(h1, h0, w4, 1);
265
266    // Rounds 40..60
267    w0 = schedule!(w1, w2, w3, w4);
268    h1 = rounds4!(h0, h1, w0, 2);
269    w1 = schedule!(w2, w3, w4, w0);
270    h0 = rounds4!(h1, h0, w1, 2);
271    w2 = schedule!(w3, w4, w0, w1);
272    h1 = rounds4!(h0, h1, w2, 2);
273    w3 = schedule!(w4, w0, w1, w2);
274    h0 = rounds4!(h1, h0, w3, 2);
275    w4 = schedule!(w0, w1, w2, w3);
276    h1 = rounds4!(h0, h1, w4, 2);
277
278    // Rounds 60..80
279    w0 = schedule!(w1, w2, w3, w4);
280    h0 = rounds4!(h1, h0, w0, 3);
281    w1 = schedule!(w2, w3, w4, w0);
282    h1 = rounds4!(h0, h1, w1, 3);
283    w2 = schedule!(w3, w4, w0, w1);
284    h0 = rounds4!(h1, h0, w2, 3);
285    w3 = schedule!(w4, w0, w1, w2);
286    h1 = rounds4!(h0, h1, w3, 3);
287    w4 = schedule!(w0, w1, w2, w3);
288    h0 = rounds4!(h1, h0, w4, 3);
289
290    let e = sha1_first(h1).rotate_left(30);
291    let u32x4(a, b, c, d) = h0;
292
293    state[0] = state[0].wrapping_add(a);
294    state[1] = state[1].wrapping_add(b);
295    state[2] = state[2].wrapping_add(c);
296    state[3] = state[3].wrapping_add(d);
297    state[4] = state[4].wrapping_add(e);
298}
299
300/// Process a block with the SHA-1 algorithm. (See more...)
301///
302/// SHA-1 is a cryptographic hash function, and as such, it operates
303/// on an arbitrary number of bytes. This function operates on a fixed
304/// number of bytes. If you call this function with anything other than
305/// 64 bytes, then it will panic! This function takes two arguments:
306///
307/// * `state` is reference to an **array** of 5 words.
308/// * `block` is reference to a **slice** of 64 bytes.
309///
310/// If you want the function that performs a message digest on an arbitrary
311/// number of bytes, then see also the `Sha1` struct above.
312///
313/// # Implementation
314///
315/// First, some background. Both ARM and Intel are releasing documentation
316/// that they plan to include instruction set extensions for SHA1 and SHA256
317/// sometime in the near future. Second, LLVM won't lower these intrinsics yet,
318/// so these functions were written emulate these instructions. Finally,
319/// the block function implemented with these emulated intrinsics turned out
320/// to be quite fast! What follows is a discussion of this CPU-level view
321/// of the SHA-1 algorithm and how it relates to the mathematical definition.
322///
323/// The SHA instruction set extensions can be divided up into two categories:
324///
325/// * message work schedule update calculation ("schedule" v., "work" n.)
326/// * message block 80-round digest calculation ("digest" v., "block" n.)
327///
328/// The schedule-related functions can be used to easily perform 4 rounds
329/// of the message work schedule update calculation, as shown below:
330///
331/// ```ignore
332/// macro_rules! schedule_x4 {
333///     ($v0:expr, $v1:expr, $v2:expr, $v3:expr) => (
334///         sha1msg2(sha1msg1($v0, $v1) ^ $v2, $v3)
335///     )
336/// }
337///
338/// macro_rules! round_x4 {
339///     ($h0:ident, $h1:ident, $wk:expr, $i:expr) => (
340///         sha1rnds4($h0, sha1_first_half($h1, $wk), $i)
341///     )
342/// }
343/// ```
344///
345/// and also shown above is how the digest-related functions can be used to
346/// perform 4 rounds of the message block digest calculation.
347///
348pub fn sha1_digest_block(state: &mut [u32; 5], block: &[u8/*; 64*/]) {
349    assert_eq!(block.len(), BLOCK_LEN*4);
350    let mut block2 = [0u32; BLOCK_LEN];
351    read_u32v_be(&mut block2[..], block);
352    sha1_digest_block_u32(state, &block2);
353}
354
355fn add_input(st: &mut Sha1, msg: &[u8]) {
356    assert!((!st.computed));
357    // Assumes that msg.len() can be converted to u64 without overflow
358    st.length_bits = add_bytes_to_bits(st.length_bits, msg.len() as u64);
359    let st_h = &mut st.h;
360    st.buffer.input(msg, |d: &[u8]| { sha1_digest_block(st_h, d); });
361}
362
363fn mk_result(st: &mut Sha1, rs: &mut [u8]) {
364    if !st.computed {
365        let st_h = &mut st.h;
366        st.buffer.standard_padding(8, |d: &[u8]| { sha1_digest_block(&mut *st_h, d) });
367        write_u32_be(st.buffer.next(4), (st.length_bits >> 32) as u32 );
368        write_u32_be(st.buffer.next(4), st.length_bits as u32);
369        sha1_digest_block(st_h, st.buffer.full_buffer());
370
371        st.computed = true;
372    }
373
374    write_u32_be(&mut rs[0..4], st.h[0]);
375    write_u32_be(&mut rs[4..8], st.h[1]);
376    write_u32_be(&mut rs[8..12], st.h[2]);
377    write_u32_be(&mut rs[12..16], st.h[3]);
378    write_u32_be(&mut rs[16..20], st.h[4]);
379}
380
381/// Structure representing the state of a Sha1 computation
382#[derive(Clone, Copy)]
383pub struct Sha1 {
384    h: [u32; STATE_LEN],
385    length_bits: u64,
386    buffer: FixedBuffer64,
387    computed: bool,
388}
389
390impl Sha1 {
391    /// Construct a `sha` object
392    pub fn new() -> Sha1 {
393        let mut st = Sha1 {
394            h: [0u32; STATE_LEN],
395            length_bits: 0u64,
396            buffer: FixedBuffer64::new(),
397            computed: false,
398        };
399        st.reset();
400        st
401    }
402}
403
404impl Digest for Sha1 {
405    fn reset(&mut self) {
406        self.length_bits = 0;
407        self.h[0] = 0x67452301u32;
408        self.h[1] = 0xEFCDAB89u32;
409        self.h[2] = 0x98BADCFEu32;
410        self.h[3] = 0x10325476u32;
411        self.h[4] = 0xC3D2E1F0u32;
412        self.buffer.reset();
413        self.computed = false;
414    }
415    fn input(&mut self, msg: &[u8]) { add_input(self, msg); }
416    fn result(&mut self, out: &mut [u8]) { mk_result(self, out) }
417    fn output_bits(&self) -> usize { 160 }
418    fn block_size(&self) -> usize { 64 }
419}
420
421#[cfg(test)]
422mod tests {
423    use cryptoutil::test::test_digest_1million_random;
424    use digest::Digest;
425    use sha1::Sha1;
426
427    #[derive(Clone)]
428    struct Test {
429        input: &'static str,
430        output: Vec<u8>,
431        output_str: &'static str,
432    }
433
434    #[test]
435    fn test() {
436        let tests = vec![
437            // Test messages from FIPS 180-1
438            Test {
439                input: "abc",
440                output: vec![
441                    0xA9u8, 0x99u8, 0x3Eu8, 0x36u8,
442                    0x47u8, 0x06u8, 0x81u8, 0x6Au8,
443                    0xBAu8, 0x3Eu8, 0x25u8, 0x71u8,
444                    0x78u8, 0x50u8, 0xC2u8, 0x6Cu8,
445                    0x9Cu8, 0xD0u8, 0xD8u8, 0x9Du8,
446                ],
447                output_str: "a9993e364706816aba3e25717850c26c9cd0d89d"
448            },
449            Test {
450                input:
451                     "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
452                output: vec![
453                    0x84u8, 0x98u8, 0x3Eu8, 0x44u8,
454                    0x1Cu8, 0x3Bu8, 0xD2u8, 0x6Eu8,
455                    0xBAu8, 0xAEu8, 0x4Au8, 0xA1u8,
456                    0xF9u8, 0x51u8, 0x29u8, 0xE5u8,
457                    0xE5u8, 0x46u8, 0x70u8, 0xF1u8,
458                ],
459                output_str: "84983e441c3bd26ebaae4aa1f95129e5e54670f1"
460            },
461            // Examples from wikipedia
462            Test {
463                input: "The quick brown fox jumps over the lazy dog",
464                output: vec![
465                    0x2fu8, 0xd4u8, 0xe1u8, 0xc6u8,
466                    0x7au8, 0x2du8, 0x28u8, 0xfcu8,
467                    0xedu8, 0x84u8, 0x9eu8, 0xe1u8,
468                    0xbbu8, 0x76u8, 0xe7u8, 0x39u8,
469                    0x1bu8, 0x93u8, 0xebu8, 0x12u8,
470                ],
471                output_str: "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12",
472            },
473            Test {
474                input: "The quick brown fox jumps over the lazy cog",
475                output: vec![
476                    0xdeu8, 0x9fu8, 0x2cu8, 0x7fu8,
477                    0xd2u8, 0x5eu8, 0x1bu8, 0x3au8,
478                    0xfau8, 0xd3u8, 0xe8u8, 0x5au8,
479                    0x0bu8, 0xd1u8, 0x7du8, 0x9bu8,
480                    0x10u8, 0x0du8, 0xb4u8, 0xb3u8,
481                ],
482                output_str: "de9f2c7fd25e1b3afad3e85a0bd17d9b100db4b3",
483            },
484        ];
485
486        // Test that it works when accepting the message all at once
487
488        let mut out = [0u8; 20];
489
490        let mut sh = Box::new(Sha1::new());
491        for t in tests.iter() {
492            (*sh).input_str(t.input);
493            sh.result(&mut out);
494            assert!(t.output[..] == out[..]);
495
496            let out_str = (*sh).result_str();
497            assert_eq!(out_str.len(), 40);
498            assert!(&out_str[..] == t.output_str);
499
500            sh.reset();
501        }
502
503
504        // Test that it works when accepting the message in pieces
505        for t in tests.iter() {
506            let len = t.input.len();
507            let mut left = len;
508            while left > 0 {
509                let take = (left + 1) / 2;
510                (*sh).input_str(&t.input[len - left..take + len - left]);
511                left = left - take;
512            }
513            sh.result(&mut out);
514            assert!(t.output[..] == out[..]);
515
516            let out_str = (*sh).result_str();
517            assert_eq!(out_str.len(), 40);
518            assert!(&out_str[..] == t.output_str);
519
520            sh.reset();
521        }
522    }
523
524    #[test]
525    fn test_1million_random_sha1() {
526        let mut sh = Sha1::new();
527        test_digest_1million_random(
528            &mut sh,
529            64,
530            "34aa973cd4c4daa4f61eeb2bdbad27316534016f");
531    }
532}
533
534#[cfg(all(test, feature = "with-bench"))]
535mod bench {
536    use test::Bencher;
537    use digest::Digest;
538    use sha1::{STATE_LEN, BLOCK_LEN};
539    use sha1::{Sha1, sha1_digest_block_u32};
540
541    #[bench]
542    pub fn sha1_block(bh: & mut Bencher) {
543        let mut state = [0u32; STATE_LEN];
544        let words = [1u32; BLOCK_LEN];
545        bh.iter( || {
546            sha1_digest_block_u32(&mut state, &words);
547        });
548        bh.bytes = 64u64;
549    }
550
551    #[bench]
552    pub fn sha1_10(bh: & mut Bencher) {
553        let mut sh = Sha1::new();
554        let bytes = [1u8; 10];
555        bh.iter( || {
556            sh.input(&bytes);
557        });
558        bh.bytes = bytes.len() as u64;
559    }
560
561    #[bench]
562    pub fn sha1_1k(bh: & mut Bencher) {
563        let mut sh = Sha1::new();
564        let bytes = [1u8; 1024];
565        bh.iter( || {
566            sh.input(&bytes);
567        });
568        bh.bytes = bytes.len() as u64;
569    }
570
571    #[bench]
572    pub fn sha1_64k(bh: & mut Bencher) {
573        let mut sh = Sha1::new();
574        let bytes = [1u8; 65536];
575        bh.iter( || {
576            sh.input(&bytes);
577        });
578        bh.bytes = bytes.len() as u64;
579    }
580
581}