• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 /// Trait for SHA2 256-bit hash implementation.
16 pub trait Sha256 {
17     /// Computes the SHA2 256-bit hash.
sha256(input: &[u8]) -> [u8; 32]18     fn sha256(input: &[u8]) -> [u8; 32];
19 }
20 
21 /// Trait for SHA2 512-bit hash implementation.
22 pub trait Sha512 {
23     /// Computes the SHA2 512-bit hash.
sha512(input: &[u8]) -> [u8; 64]24     fn sha512(input: &[u8]) -> [u8; 64];
25 }
26 
27 /// Utilities for testing. Implementations can use the test cases and functions provided to test
28 /// their implementation.
29 #[cfg(feature = "testing")]
30 pub mod testing {
31 
32     extern crate alloc;
33     extern crate std;
34     use super::{Sha256, Sha512};
35     pub use crate::testing::prelude::*;
36     use crate::CryptoProvider;
37     use alloc::vec::Vec;
38     use core::{marker::PhantomData, str::FromStr};
39     use hex::FromHex;
40     pub use hex_literal::hex;
41     use rstest_reuse::template;
42 
43     /// Test vectors from SHA256ShortMsg.rsp in
44     /// <https://csrc.nist.gov/projects/cryptographic-algorithm-validation-program/secure-hashing#shavs>
sha256_cavp_short_vector_test<C: CryptoProvider>(_marker: PhantomData<C>)45     pub fn sha256_cavp_short_vector_test<C: CryptoProvider>(_marker: PhantomData<C>) {
46         sha256_cavp_vector_test::<C>(include_str!("testdata/SHA256ShortMsg.rsp"));
47     }
48 
49     /// Test vectors from SHA256LongMsg.rsp in
50     /// <https://csrc.nist.gov/projects/cryptographic-algorithm-validation-program/secure-hashing#shavs>
sha256_cavp_long_vector_test<C: CryptoProvider>(_marker: PhantomData<C>)51     pub fn sha256_cavp_long_vector_test<C: CryptoProvider>(_marker: PhantomData<C>) {
52         sha256_cavp_vector_test::<C>(include_str!("testdata/SHA256LongMsg.rsp"));
53     }
54 
55     /// Test vectors from SHA512ShortMsg.rsp in
56     /// <https://csrc.nist.gov/projects/cryptographic-algorithm-validation-program/secure-hashing#shavs>
sha512_cavp_short_vector_test<C: CryptoProvider>(_marker: PhantomData<C>)57     pub fn sha512_cavp_short_vector_test<C: CryptoProvider>(_marker: PhantomData<C>) {
58         sha512_cavp_vector_test::<C>(include_str!("testdata/SHA512ShortMsg.rsp"));
59     }
60 
61     /// Test vectors from SHA512LongMsg.rsp in
62     /// <https://csrc.nist.gov/projects/cryptographic-algorithm-validation-program/secure-hashing#shavs>
sha512_cavp_long_vector_test<C: CryptoProvider>(_marker: PhantomData<C>)63     pub fn sha512_cavp_long_vector_test<C: CryptoProvider>(_marker: PhantomData<C>) {
64         sha512_cavp_vector_test::<C>(include_str!("testdata/SHA512LongMsg.rsp"));
65     }
66 
67     /// Test vectors an rsp file in
68     /// <https://csrc.nist.gov/projects/cryptographic-algorithm-validation-program/secure-hashing#shavs>
sha256_cavp_vector_test<C: CryptoProvider>(cavp_file_contents: &str)69     fn sha256_cavp_vector_test<C: CryptoProvider>(cavp_file_contents: &str) {
70         sha_cavp_vector_test(<C::Sha256 as Sha256>::sha256, cavp_file_contents)
71     }
72 
73     /// Test vectors an rsp file in
74     /// <https://csrc.nist.gov/projects/cryptographic-algorithm-validation-program/secure-hashing#shavs>
sha512_cavp_vector_test<C: CryptoProvider>(cavp_file_contents: &str)75     fn sha512_cavp_vector_test<C: CryptoProvider>(cavp_file_contents: &str) {
76         sha_cavp_vector_test(<C::Sha512 as Sha512>::sha512, cavp_file_contents)
77     }
78 
sha_cavp_vector_test<const N: usize>( hash_func: impl Fn(&[u8]) -> [u8; N], cavp_file_contents: &str, )79     fn sha_cavp_vector_test<const N: usize>(
80         hash_func: impl Fn(&[u8]) -> [u8; N],
81         cavp_file_contents: &str,
82     ) {
83         let test_cases = cavp_file_contents.split("\n\n").filter_map(|chunk| {
84             let mut len: Option<usize> = None;
85             let mut msg: Option<Vec<u8>> = None;
86             let mut md: Option<Vec<u8>> = None;
87             for line in chunk.split('\n') {
88                 if line.starts_with('#') || line.is_empty() || line == std::format!("[L = {N}]") {
89                     continue;
90                 } else if let Some(len_str) = line.strip_prefix("Len = ") {
91                     len = Some(FromStr::from_str(len_str).unwrap());
92                 } else if let Some(hex_str) = line.strip_prefix("Msg = ") {
93                     msg = Some(Vec::<u8>::from_hex(hex_str).unwrap());
94                 } else if let Some(hex_str) = line.strip_prefix("MD = ") {
95                     md = Some(Vec::<u8>::from_hex(hex_str).unwrap());
96                 } else {
97                     panic!("Unexpected line in test file: `{}`", line);
98                 }
99             }
100             if let (Some(len), Some(msg), Some(md)) = (len, msg, md) {
101                 Some((len, msg, md))
102             } else {
103                 None
104             }
105         });
106         for (len, mut msg, md) in test_cases {
107             if len == 0 {
108                 // Truncate len = 0, since the test file has "Msg = 00" in there that should be
109                 // ignored.
110                 msg.truncate(0);
111             }
112             assert_eq!(msg.len(), len / 8);
113             let md_arr: [u8; N] = md.try_into().unwrap();
114             assert_eq!(hash_func(&msg), md_arr);
115         }
116     }
117 
118     /// Generates the test cases to validate the SHA2 implementation.
119     /// For example, to test `MyCryptoProvider`:
120     ///
121     /// ```
122     /// use crypto_provider::sha2::testing::*;
123     ///
124     /// mod tests {
125     ///     #[apply(sha2_test_cases)]
126     ///     fn sha2_tests(testcase: CryptoProviderTestCase<MyCryptoProvider>) {
127     ///         testcase(PhantomData::<MyCryptoProvider>);
128     ///     }
129     /// }
130     /// ```
131     #[template]
132     #[export]
133     #[rstest]
134     #[case::sha256_cavp_short_vector(sha256_cavp_short_vector_test)]
135     #[case::sha256_cavp_long_vector(sha256_cavp_long_vector_test)]
sha2_test_cases<C: CryptoProvider>(#[case] testcase: CryptoProviderTestCase<C>)136     fn sha2_test_cases<C: CryptoProvider>(#[case] testcase: CryptoProviderTestCase<C>) {}
137 }
138