diff --git a/Cargo.lock b/Cargo.lock index f981de29e..840a2d2f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -290,6 +290,7 @@ dependencies = [ "cfg-if", "cpufeatures", "digest", + "hex", "hex-literal", ] diff --git a/sha1/Cargo.toml b/sha1/Cargo.toml index 34c078b61..882d19e8d 100644 --- a/sha1/Cargo.toml +++ b/sha1/Cargo.toml @@ -21,6 +21,7 @@ cpufeatures = "0.3" [dev-dependencies] digest = { version = "0.11", features = ["dev"] } +hex = "0.4.3" hex-literal = "1" [features] diff --git a/sha1/tests/mod.rs b/sha1/tests/mod.rs index 92858ae3f..e1fd8433b 100644 --- a/sha1/tests/mod.rs +++ b/sha1/tests/mod.rs @@ -1,10 +1,24 @@ use digest::dev::{feed_rand_16mib, fixed_reset_test}; use hex_literal::hex; use sha1::{Digest, Sha1}; +use std::fs; +use std::path::Path; +use std::time::{SystemTime, UNIX_EPOCH}; digest::new_test!(sha1_kat, Sha1, fixed_reset_test); digest::hash_serialization_test!(sha1_serialization, Sha1); +fn sha1_hex(bytes: &[u8]) -> String { + let mut hasher = Sha1::new(); + hasher.update(bytes); + hex::encode(hasher.finalize()) +} + +fn sha1_file_hex(path: impl AsRef) -> std::io::Result { + let bytes = fs::read(path)?; + Ok(sha1_hex(&bytes)) +} + #[test] fn sha1_rand() { let mut h = Sha1::new(); @@ -14,3 +28,63 @@ fn sha1_rand() { hex!("7e565a25a8b123e9881addbcedcd927b23377a78"), ); } + +/// +/// Test vectors from https://www.nist.gov/itl/ssd/software-quality-group/nsrl-test-data for SHA-1. +/// + +/// A file containing the ASCII string "abc" results in a 160 bit message digest of +/// a9993e364706816aba3e25717850c26c9cd0d89d +#[test] +fn abc_file_has_expected_sha1_digest() { + let unique = SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("system time should be after the unix epoch") + .as_nanos(); + let path = std::env::temp_dir().join(format!("tester-sha1-{unique}.txt")); + + fs::write(&path, b"abc").expect("should write test file"); + let digest = sha1_file_hex(&path).expect("should hash test file"); + + let _ = fs::remove_file(&path); + + assert_eq!(digest, "a9993e364706816aba3e25717850c26c9cd0d89d"); +} + +/// A file containing the ASCII string "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" +/// results in a 160-bit message digest of 84983e441c3bd26ebaae4aa1f95129e5e54670f1. +#[test] +fn long_test_vector_file_has_expected_sha1_digest() { + let unique = SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("system time should be after the unix epoch") + .as_nanos(); + let path = std::env::temp_dir().join(format!("tester-sha1-{unique}.txt")); + let contents = b"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; + + fs::write(&path, contents).expect("should write test file"); + let digest = sha1_file_hex(&path).expect("should hash test file"); + + let _ = fs::remove_file(&path); + + assert_eq!(digest, "84983e441c3bd26ebaae4aa1f95129e5e54670f1"); +} + +/// A file containing the binary-coded form of the ASCII string which consists of 1,000,000 repetitions of the character "a" results +/// in a SHA-1 message digest of 34aa973cd4c4daa4f61eeb2bdbad27316534016f. +#[test] +fn one_million_a_file_has_expected_sha1_digest() { + let unique = SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("system time should be after the unix epoch") + .as_nanos(); + let path = std::env::temp_dir().join(format!("tester-sha1-{unique}.txt")); + let bytes: Vec = std::iter::repeat(b'a').take(1_000_000).collect(); + + fs::write(&path, bytes).expect("should write test file"); + let digest = sha1_file_hex(&path).expect("should hash test file"); + + let _ = fs::remove_file(&path); + + assert_eq!(digest, "34aa973cd4c4daa4f61eeb2bdbad27316534016f"); +}