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}