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