1 // Copyright 2023 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 extern crate alloc;
16 extern crate std;
17 use crate::prelude::*;
18 use crate::CryptoProvider;
19 use core::{marker::PhantomData, str::FromStr};
20 use crypto_provider::sha2::{Sha256, Sha512};
21 use hex::FromHex;
22 pub use hex_literal::hex;
23 use rstest_reuse::template;
24
25 /// Test vectors from SHA256ShortMsg.rsp in
26 /// <https://csrc.nist.gov/projects/cryptographic-algorithm-validation-program/secure-hashing#shavs>
sha256_cavp_short_vector_test<C: CryptoProvider>(_marker: PhantomData<C>)27 pub fn sha256_cavp_short_vector_test<C: CryptoProvider>(_marker: PhantomData<C>) {
28 sha256_cavp_vector_test::<C>(include_str!("testdata/SHA256ShortMsg.rsp"));
29 }
30
31 /// Test vectors from SHA256LongMsg.rsp in
32 /// <https://csrc.nist.gov/projects/cryptographic-algorithm-validation-program/secure-hashing#shavs>
sha256_cavp_long_vector_test<C: CryptoProvider>(_marker: PhantomData<C>)33 pub fn sha256_cavp_long_vector_test<C: CryptoProvider>(_marker: PhantomData<C>) {
34 sha256_cavp_vector_test::<C>(include_str!("testdata/SHA256LongMsg.rsp"));
35 }
36
37 /// Test vectors from SHA512ShortMsg.rsp in
38 /// <https://csrc.nist.gov/projects/cryptographic-algorithm-validation-program/secure-hashing#shavs>
sha512_cavp_short_vector_test<C: CryptoProvider>(_marker: PhantomData<C>)39 pub fn sha512_cavp_short_vector_test<C: CryptoProvider>(_marker: PhantomData<C>) {
40 sha512_cavp_vector_test::<C>(include_str!("testdata/SHA512ShortMsg.rsp"));
41 }
42
43 /// Test vectors from SHA512LongMsg.rsp in
44 /// <https://csrc.nist.gov/projects/cryptographic-algorithm-validation-program/secure-hashing#shavs>
sha512_cavp_long_vector_test<C: CryptoProvider>(_marker: PhantomData<C>)45 pub fn sha512_cavp_long_vector_test<C: CryptoProvider>(_marker: PhantomData<C>) {
46 sha512_cavp_vector_test::<C>(include_str!("testdata/SHA512LongMsg.rsp"));
47 }
48
49 /// Test vectors an rsp file in
50 /// <https://csrc.nist.gov/projects/cryptographic-algorithm-validation-program/secure-hashing#shavs>
sha256_cavp_vector_test<C: CryptoProvider>(cavp_file_contents: &str)51 fn sha256_cavp_vector_test<C: CryptoProvider>(cavp_file_contents: &str) {
52 sha_cavp_vector_test(<C::Sha256 as Sha256>::sha256, cavp_file_contents)
53 }
54
55 /// Test vectors an rsp file in
56 /// <https://csrc.nist.gov/projects/cryptographic-algorithm-validation-program/secure-hashing#shavs>
sha512_cavp_vector_test<C: CryptoProvider>(cavp_file_contents: &str)57 fn sha512_cavp_vector_test<C: CryptoProvider>(cavp_file_contents: &str) {
58 sha_cavp_vector_test(<C::Sha512 as Sha512>::sha512, cavp_file_contents)
59 }
60
sha_cavp_vector_test<const N: usize>( hash_func: impl Fn(&[u8]) -> [u8; N], cavp_file_contents: &str, )61 fn sha_cavp_vector_test<const N: usize>(
62 hash_func: impl Fn(&[u8]) -> [u8; N],
63 cavp_file_contents: &str,
64 ) {
65 let test_cases = cavp_file_contents.split("\n\n").filter_map(|chunk| {
66 let mut len: Option<usize> = None;
67 let mut msg: Option<Vec<u8>> = None;
68 let mut md: Option<Vec<u8>> = None;
69 for line in chunk.split('\n') {
70 if line.starts_with('#') || line.is_empty() || line == std::format!("[L = {N}]") {
71 continue;
72 } else if let Some(len_str) = line.strip_prefix("Len = ") {
73 len = Some(FromStr::from_str(len_str).unwrap());
74 } else if let Some(hex_str) = line.strip_prefix("Msg = ") {
75 msg = Some(Vec::<u8>::from_hex(hex_str).unwrap());
76 } else if let Some(hex_str) = line.strip_prefix("MD = ") {
77 md = Some(Vec::<u8>::from_hex(hex_str).unwrap());
78 } else {
79 panic!("Unexpected line in test file: `{}`", line);
80 }
81 }
82 if let (Some(len), Some(msg), Some(md)) = (len, msg, md) {
83 Some((len, msg, md))
84 } else {
85 None
86 }
87 });
88 for (len, mut msg, md) in test_cases {
89 if len == 0 {
90 // Truncate len = 0, since the test file has "Msg = 00" in there that should be
91 // ignored.
92 msg.truncate(0);
93 }
94 assert_eq!(msg.len(), len / 8);
95 let md_arr: [u8; N] = md.try_into().unwrap();
96 assert_eq!(hash_func(&msg), md_arr);
97 }
98 }
99
100 /// Generates the test cases to validate the SHA2 implementation.
101 /// For example, to test `MyCryptoProvider`:
102 ///
103 /// ```
104 /// use crypto_provider::sha2::testing::*;
105 ///
106 /// mod tests {
107 /// #[apply(sha2_test_cases)]
108 /// fn sha2_tests(testcase: CryptoProviderTestCase<MyCryptoProvider>) {
109 /// testcase(PhantomData::<MyCryptoProvider>);
110 /// }
111 /// }
112 /// ```
113 #[template]
114 #[export]
115 #[rstest]
116 #[case::sha256_cavp_short_vector(sha256_cavp_short_vector_test)]
117 #[case::sha256_cavp_long_vector(sha256_cavp_long_vector_test)]
sha2_test_cases<C: CryptoProvider>(#[case] testcase: CryptoProviderTestCase<C>)118 fn sha2_test_cases<C: CryptoProvider>(#[case] testcase: CryptoProviderTestCase<C>) {}
119