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 extern crate alloc;
15 
16 use alloc::format;
17 use core::marker::PhantomData;
18 
19 use crypto_provider::CryptoProvider;
20 use hex_literal::hex;
21 use rand::{Rng, RngCore};
22 use rstest_reuse::template;
23 
24 pub use rstest_reuse;
25 
26 pub mod aead;
27 pub mod aes;
28 pub mod ed25519;
29 pub mod elliptic_curve;
30 pub mod hkdf;
31 pub mod hmac;
32 pub mod p256;
33 pub mod sha2;
34 pub mod x25519;
35 
36 /// Common items that needs to be imported to use these test cases
37 pub mod prelude {
38     pub use super::CryptoProviderTestCase;
39     pub use ::rstest;
40     pub use rstest::rstest;
41     pub use rstest_reuse;
42     pub use rstest_reuse::apply;
43     pub extern crate std;
44 }
45 
46 /// A test case for Crypto Provider. A test case is a function that panics if the test fails.
47 pub type CryptoProviderTestCase<T> = fn(PhantomData<T>);
48 
49 #[derive(Debug)]
50 pub(crate) struct TestError(#[allow(unused)] String);
51 
52 impl TestError {
new<D: core::fmt::Debug>(value: D) -> Self53     pub(crate) fn new<D: core::fmt::Debug>(value: D) -> Self {
54         Self(format!("{value:?}"))
55     }
56 }
57 
58 /// Test for `constant_time_eq` when the two inputs are equal.
constant_time_eq_test_equal<C: CryptoProvider>(_marker: PhantomData<C>)59 pub fn constant_time_eq_test_equal<C: CryptoProvider>(_marker: PhantomData<C>) {
60     assert!(C::constant_time_eq(&hex!("00010203040506070809"), &hex!("00010203040506070809")));
61 }
62 
63 /// Test for `constant_time_eq` when the two inputs are not equal.
constant_time_eq_test_not_equal<C: CryptoProvider>(_marker: PhantomData<C>)64 pub fn constant_time_eq_test_not_equal<C: CryptoProvider>(_marker: PhantomData<C>) {
65     assert!(!C::constant_time_eq(&hex!("00010203040506070809"), &hex!("00000000000000000000")));
66 }
67 
68 /// Random tests for `constant_time_eq`.
constant_time_eq_random_test<C: CryptoProvider>(_marker: PhantomData<C>)69 pub fn constant_time_eq_random_test<C: CryptoProvider>(_marker: PhantomData<C>) {
70     let mut rng = rand::thread_rng();
71     for _ in 1..100 {
72         // Test using "oracle" of ==, with possibly different lengths for a and b
73         let mut a = alloc::vec![0; rng.gen_range(1..1000)];
74         rng.fill_bytes(&mut a);
75         let mut b = alloc::vec![0; rng.gen_range(1..1000)];
76         rng.fill_bytes(&mut b);
77         assert_eq!(C::constant_time_eq(&a, &b), a == b);
78     }
79 
80     for _ in 1..10000 {
81         // Test using "oracle" of ==, with same lengths for a and b
82         let len = rng.gen_range(1..1000);
83         let mut a = alloc::vec![0; len];
84         rng.fill_bytes(&mut a);
85         let mut b = alloc::vec![0; len];
86         rng.fill_bytes(&mut b);
87         assert_eq!(C::constant_time_eq(&a, &b), a == b);
88     }
89 
90     for _ in 1..10000 {
91         // Clones and the original should always be equal
92         let mut a = alloc::vec![0; rng.gen_range(1..1000)];
93         rng.fill_bytes(&mut a);
94         assert!(C::constant_time_eq(&a, &a.clone()));
95     }
96 }
97 
98 /// Generates the test cases to validate the P256 implementation.
99 /// For example, to test `MyCryptoProvider`:
100 ///
101 /// ```
102 /// use crypto_provider::p256::testing::*;
103 ///
104 /// mod tests {
105 ///     #[apply(constant_time_eq_test_cases)]
106 ///     fn constant_time_eq_tests(
107 ///             testcase: CryptoProviderTestCase<MyCryptoProvider>) {
108 ///         testcase(PhantomData);
109 ///     }
110 /// }
111 /// ```
112 #[template]
113 #[export]
114 #[rstest]
115 #[case::constant_time_eq_test_not_equal(constant_time_eq_test_not_equal)]
116 #[case::constant_time_eq_test_equal(constant_time_eq_test_equal)]
117 #[case::constant_time_eq_random_test(constant_time_eq_random_test)]
constant_time_eq_test_cases<C: CryptoProvider>(#[case] testcase: CryptoProviderTestCase<C>)118 fn constant_time_eq_test_cases<C: CryptoProvider>(#[case] testcase: CryptoProviderTestCase<C>) {}
119