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