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