• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015-2017 Brian Smith.
2 //
3 // Permission to use, copy, modify, and/or distribute this software for any
4 // purpose with or without fee is hereby granted, provided that the above
5 // copyright notice and this permission notice appear in all copies.
6 //
7 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
8 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
10 // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 
15 use ring::{digest, test, test_file};
16 
17 #[cfg(target_arch = "wasm32")]
18 use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure};
19 
20 #[cfg(target_arch = "wasm32")]
21 wasm_bindgen_test_configure!(run_in_browser);
22 
23 /// Test vectors from BoringSSL, Go, and other sources.
24 #[test]
digest_misc()25 fn digest_misc() {
26     test::run(test_file!("digest_tests.txt"), |section, test_case| {
27         assert_eq!(section, "");
28         let digest_alg = test_case.consume_digest_alg("Hash").unwrap();
29         let input = test_case.consume_bytes("Input");
30         let repeat = test_case.consume_usize("Repeat");
31         let expected = test_case.consume_bytes("Output");
32 
33         let mut ctx = digest::Context::new(digest_alg);
34         let mut data = Vec::new();
35         for _ in 0..repeat {
36             ctx.update(&input);
37             data.extend(&input);
38         }
39         let actual_from_chunks = ctx.finish();
40         assert_eq!(&expected, &actual_from_chunks.as_ref());
41 
42         let actual_from_one_shot = digest::digest(digest_alg, &data);
43         assert_eq!(&expected, &actual_from_one_shot.as_ref());
44 
45         Ok(())
46     });
47 }
48 
49 // wasm_bindgen doesn't build this correctly.
50 #[cfg(not(target_arch = "wsam32"))]
51 mod digest_shavs {
52     use ring::{digest, test};
53 
run_known_answer_test(digest_alg: &'static digest::Algorithm, test_file: test::File)54     fn run_known_answer_test(digest_alg: &'static digest::Algorithm, test_file: test::File) {
55         let section_name = &format!("L = {}", digest_alg.output_len);
56         test::run(test_file, |section, test_case| {
57             assert_eq!(section_name, section);
58             let len_bits = test_case.consume_usize("Len");
59 
60             let mut msg = test_case.consume_bytes("Msg");
61             // The "msg" field contains the dummy value "00" when the
62             // length is zero.
63             if len_bits == 0 {
64                 assert_eq!(msg, &[0u8]);
65                 msg.truncate(0);
66             }
67 
68             assert_eq!(msg.len() * 8, len_bits);
69             let expected = test_case.consume_bytes("MD");
70             let actual = digest::digest(digest_alg, &msg);
71             assert_eq!(&expected, &actual.as_ref());
72 
73             Ok(())
74         });
75     }
76 
77     macro_rules! shavs_tests {
78         ( $file_name:ident, $algorithm_name:ident ) => {
79             #[allow(non_snake_case)]
80             mod $algorithm_name {
81                 use super::{run_known_answer_test, run_monte_carlo_test};
82                 use ring::{digest, test_file};
83 
84                 #[cfg(target_arch = "wasm32")]
85                 use wasm_bindgen_test::wasm_bindgen_test as test;
86 
87                 #[test]
88                 fn short_msg_known_answer_test() {
89                     run_known_answer_test(
90                         &digest::$algorithm_name,
91                         test_file!(concat!(
92                             "../third_party/NIST/SHAVS/",
93                             stringify!($file_name),
94                             "ShortMsg.rsp"
95                         )),
96                     );
97                 }
98 
99                 #[test]
100                 fn long_msg_known_answer_test() {
101                     run_known_answer_test(
102                         &digest::$algorithm_name,
103                         test_file!(concat!(
104                             "../third_party/NIST/SHAVS/",
105                             stringify!($file_name),
106                             "LongMsg.rsp"
107                         )),
108                     );
109                 }
110 
111                 #[test]
112                 fn monte_carlo_test() {
113                     run_monte_carlo_test(
114                         &digest::$algorithm_name,
115                         test_file!(concat!(
116                             "../third_party/NIST/SHAVS/",
117                             stringify!($file_name),
118                             "Monte.rsp"
119                         )),
120                     );
121                 }
122             }
123         };
124     }
125 
run_monte_carlo_test(digest_alg: &'static digest::Algorithm, test_file: test::File)126     fn run_monte_carlo_test(digest_alg: &'static digest::Algorithm, test_file: test::File) {
127         let section_name = &format!("L = {}", digest_alg.output_len);
128 
129         let mut expected_count: isize = -1;
130         let mut seed = Vec::with_capacity(digest_alg.output_len);
131 
132         test::run(test_file, |section, test_case| {
133             assert_eq!(section_name, section);
134 
135             if expected_count == -1 {
136                 seed.extend(test_case.consume_bytes("Seed"));
137                 expected_count = 0;
138                 return Ok(());
139             }
140 
141             assert!(expected_count >= 0);
142             let actual_count = test_case.consume_usize("COUNT");
143             assert_eq!(expected_count as usize, actual_count);
144             expected_count += 1;
145 
146             let expected_md = test_case.consume_bytes("MD");
147 
148             let mut mds = Vec::with_capacity(4);
149             mds.push(seed.clone());
150             mds.push(seed.clone());
151             mds.push(seed.clone());
152             for _ in 0..1000 {
153                 let mut ctx = digest::Context::new(digest_alg);
154                 ctx.update(&mds[0]);
155                 ctx.update(&mds[1]);
156                 ctx.update(&mds[2]);
157                 let md_i = ctx.finish();
158                 let _ = mds.remove(0);
159                 mds.push(Vec::from(md_i.as_ref()));
160             }
161             let md_j = mds.last().unwrap();
162             assert_eq!(&expected_md, md_j);
163             seed = md_j.clone();
164 
165             Ok(())
166         });
167 
168         assert_eq!(expected_count, 100);
169     }
170 
171     shavs_tests!(SHA1, SHA1_FOR_LEGACY_USE_ONLY);
172     shavs_tests!(SHA256, SHA256);
173     shavs_tests!(SHA384, SHA384);
174     shavs_tests!(SHA512, SHA512);
175 }
176 
177 /// Test some ways in which `Context::update` and/or `Context::finish`
178 /// could go wrong by testing every combination of updating three inputs
179 /// that vary from zero bytes to one byte larger than the block length.
180 ///
181 /// These are not run in dev (debug) builds because they are too slow.
182 macro_rules! test_i_u_f {
183     ( $test_name:ident, $alg:expr) => {
184         #[cfg(not(debug_assertions))]
185         // TODO: Get this working on WebAssembly
186         #[cfg(not(target_arch = "wasm32"))]
187         #[test]
188         fn $test_name() {
189             let mut input = [0; (digest::MAX_BLOCK_LEN + 1) * 3];
190             let max = $alg.block_len + 1;
191             for i in 0..(max * 3) {
192                 input[i] = (i & 0xff) as u8;
193             }
194 
195             for i in 0..max {
196                 for j in 0..max {
197                     for k in 0..max {
198                         let part1 = &input[..i];
199                         let part2 = &input[i..(i + j)];
200                         let part3 = &input[(i + j)..(i + j + k)];
201 
202                         let mut ctx = digest::Context::new(&$alg);
203                         ctx.update(part1);
204                         ctx.update(part2);
205                         ctx.update(part3);
206                         let i_u_f = ctx.finish();
207 
208                         let one_shot = digest::digest(&$alg, &input[..(i + j + k)]);
209 
210                         assert_eq!(i_u_f.as_ref(), one_shot.as_ref());
211                     }
212                 }
213             }
214         }
215     };
216 }
217 test_i_u_f!(digest_test_i_u_f_sha1, digest::SHA1_FOR_LEGACY_USE_ONLY);
218 test_i_u_f!(digest_test_i_u_f_sha256, digest::SHA256);
219 test_i_u_f!(digest_test_i_u_f_sha384, digest::SHA384);
220 test_i_u_f!(digest_test_i_u_f_sha512, digest::SHA512);
221 
222 /// See https://bugzilla.mozilla.org/show_bug.cgi?id=610162. This tests the
223 /// calculation of 8GB of the byte 123.
224 ///
225 /// You can verify the expected values in many ways. One way is
226 /// `python ~/p/write_big.py`, where write_big.py is:
227 ///
228 /// ```python
229 /// chunk = bytearray([123] * (16 * 1024))
230 /// with open('tempfile', 'w') as f:
231 /// for i in xrange(0, 8 * 1024 * 1024 * 1024, len(chunk)):
232 ///     f.write(chunk)
233 /// ```
234 /// Then:
235 ///
236 /// ```sh
237 /// sha1sum -b tempfile
238 /// sha256sum -b tempfile
239 /// sha384sum -b tempfile
240 /// sha512sum -b tempfile
241 /// ```
242 ///
243 /// This is not run in dev (debug) builds because it is too slow.
244 macro_rules! test_large_digest {
245     ( $test_name:ident, $alg:expr, $len:expr, $expected:expr) => {
246         // TODO: get this working on WebAssembly.
247         #[cfg(not(debug_assertions))]
248         #[cfg(not(target_arch = "wasm32"))]
249         #[test]
250         fn $test_name() {
251             let chunk = vec![123u8; 16 * 1024];
252             let chunk_len = chunk.len() as u64;
253             let mut ctx = digest::Context::new(&$alg);
254             let mut hashed = 0u64;
255             loop {
256                 ctx.update(&chunk);
257                 hashed += chunk_len;
258                 if hashed >= 8u64 * 1024 * 1024 * 1024 {
259                     break;
260                 }
261             }
262             let calculated = ctx.finish();
263             let expected: [u8; $len] = $expected;
264             assert_eq!(&expected[..], calculated.as_ref());
265         }
266     };
267 }
268 
269 // XXX: This test is too slow on Android ARM.
270 #[cfg(any(not(target_os = "android"), not(target_arch = "arm")))]
271 test_large_digest!(
272     digest_test_large_digest_sha1,
273     digest::SHA1_FOR_LEGACY_USE_ONLY,
274     160 / 8,
275     [
276         0xCA, 0xC3, 0x4C, 0x31, 0x90, 0x5B, 0xDE, 0x3B, 0xE4, 0x0D, 0x46, 0x6D, 0x70, 0x76, 0xAD,
277         0x65, 0x3C, 0x20, 0xE4, 0xBD
278     ]
279 );
280 
281 test_large_digest!(
282     digest_test_large_digest_sha256,
283     digest::SHA256,
284     256 / 8,
285     [
286         0x8D, 0xD1, 0x6D, 0xD8, 0xB2, 0x5A, 0x29, 0xCB, 0x7F, 0xB9, 0xAE, 0x86, 0x72, 0xE9, 0xCE,
287         0xD6, 0x65, 0x4C, 0xB6, 0xC3, 0x5C, 0x58, 0x21, 0xA7, 0x07, 0x97, 0xC5, 0xDD, 0xAE, 0x5C,
288         0x68, 0xBD
289     ]
290 );
291 test_large_digest!(
292     digest_test_large_digest_sha384,
293     digest::SHA384,
294     384 / 8,
295     [
296         0x3D, 0xFE, 0xC1, 0xA9, 0xD0, 0x9F, 0x08, 0xD5, 0xBB, 0xE8, 0x7C, 0x9E, 0xE0, 0x0A, 0x87,
297         0x0E, 0xB0, 0xEA, 0x8E, 0xEA, 0xDB, 0x82, 0x36, 0xAE, 0x74, 0xCF, 0x9F, 0xDC, 0x86, 0x1C,
298         0xE3, 0xE9, 0xB0, 0x68, 0xCD, 0x19, 0x3E, 0x39, 0x90, 0x02, 0xE1, 0x58, 0x5D, 0x66, 0xC4,
299         0x55, 0x11, 0x9B
300     ]
301 );
302 test_large_digest!(
303     digest_test_large_digest_sha512,
304     digest::SHA512,
305     512 / 8,
306     [
307         0xFC, 0x8A, 0x98, 0x20, 0xFC, 0x82, 0xD8, 0x55, 0xF8, 0xFF, 0x2F, 0x6E, 0xAE, 0x41, 0x60,
308         0x04, 0x08, 0xE9, 0x49, 0xD7, 0xCD, 0x1A, 0xED, 0x22, 0xEB, 0x55, 0xE1, 0xFD, 0x80, 0x50,
309         0x3B, 0x01, 0x2F, 0xC6, 0xF4, 0x33, 0x86, 0xFB, 0x60, 0x75, 0x2D, 0xA5, 0xA9, 0x93, 0xE7,
310         0x00, 0x45, 0xA8, 0x49, 0x1A, 0x6B, 0xEC, 0x9C, 0x98, 0xC8, 0x19, 0xA6, 0xA9, 0x88, 0x3E,
311         0x2F, 0x09, 0xB9, 0x9A
312     ]
313 );
314 
315 // TODO: test_large_digest!(digest_test_large_digest_sha512_256,
316 //                            digest::SHA512_256, 256 / 8, [ ... ]);
317 
318 #[test]
test_fmt_algorithm()319 fn test_fmt_algorithm() {
320     assert_eq!("SHA1", &format!("{:?}", digest::SHA1_FOR_LEGACY_USE_ONLY));
321     assert_eq!("SHA256", &format!("{:?}", digest::SHA256));
322     assert_eq!("SHA384", &format!("{:?}", digest::SHA384));
323     assert_eq!("SHA512", &format!("{:?}", digest::SHA512));
324     assert_eq!("SHA512_256", &format!("{:?}", digest::SHA512_256));
325 }
326 
327 #[test]
digest_test_fmt()328 fn digest_test_fmt() {
329     assert_eq!(
330         "SHA1:b7e23ec29af22b0b4e41da31e868d57226121c84",
331         &format!(
332             "{:?}",
333             digest::digest(&digest::SHA1_FOR_LEGACY_USE_ONLY, b"hello, world")
334         )
335     );
336     assert_eq!(
337         "SHA256:09ca7e4eaa6e8ae9c7d261167129184883644d\
338          07dfba7cbfbc4c8a2e08360d5b",
339         &format!("{:?}", digest::digest(&digest::SHA256, b"hello, world"))
340     );
341     assert_eq!(
342         "SHA384:1fcdb6059ce05172a26bbe2a3ccc88ed5a8cd5\
343          fc53edfd9053304d429296a6da23b1cd9e5c9ed3bb34f0\
344          0418a70cdb7e",
345         &format!("{:?}", digest::digest(&digest::SHA384, b"hello, world"))
346     );
347     assert_eq!(
348         "SHA512:8710339dcb6814d0d9d2290ef422285c9322b7\
349          163951f9a0ca8f883d3305286f44139aa374848e4174f5\
350          aada663027e4548637b6d19894aec4fb6c46a139fbf9",
351         &format!("{:?}", digest::digest(&digest::SHA512, b"hello, world"))
352     );
353 
354     assert_eq!(
355         "SHA512_256:11f2c88c04f0a9c3d0970894ad2472505e\
356          0bc6e8c7ec46b5211cd1fa3e253e62",
357         &format!("{:?}", digest::digest(&digest::SHA512_256, b"hello, world"))
358     );
359 }
360