• 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 #![no_std]
15 #![forbid(unsafe_code)]
16 #![deny(missing_docs)]
17 
18 //! Crypto abstraction trait only crate, which provides traits for cryptographic primitives
19 
20 use core::fmt::Debug;
21 
22 /// mod containing hmac trait
23 pub mod hkdf;
24 
25 /// mod containing hkdf trait
26 pub mod hmac;
27 
28 /// mod containing X25519 trait
29 pub mod x25519;
30 
31 /// mod containing traits for NIST-P256 elliptic curve implementation.
32 pub mod p256;
33 
34 /// mod containing traits for elliptic curve cryptography.
35 pub mod elliptic_curve;
36 
37 /// mod containing SHA256 trait.
38 pub mod sha2;
39 
40 /// mod containing aes trait
41 pub mod aes;
42 
43 /// mod containing traits for ed25519 key generation, signing, and verification
44 pub mod ed25519;
45 
46 /// Uber crypto trait which defines the traits for all crypto primitives as associated types
47 pub trait CryptoProvider: Clone + Debug + PartialEq + Eq + Send {
48     /// The Hkdf type which implements the hkdf trait
49     type HkdfSha256: hkdf::Hkdf;
50     /// The Hmac type which implements the hmac trait
51     type HmacSha256: hmac::Hmac<32>;
52     /// The Hkdf type which implements the hkdf trait
53     type HkdfSha512: hkdf::Hkdf;
54     /// The Hmac type which implements the hmac trait
55     type HmacSha512: hmac::Hmac<64>;
56     /// The AES-CBC-PKCS7 implementation to use
57     type AesCbcPkcs7Padded: aes::cbc::AesCbcPkcs7Padded;
58     /// The X25519 implementation to use for ECDH.
59     type X25519: elliptic_curve::EcdhProvider<x25519::X25519>;
60     /// The P256 implementation to use for ECDH.
61     type P256: p256::P256EcdhProvider;
62     /// The SHA256 hash implementation.
63     type Sha256: sha2::Sha256;
64     /// The SHA512 hash implementation.
65     type Sha512: sha2::Sha512;
66     /// Plain AES-128 implementation (without block cipher mode).
67     type Aes128: aes::Aes<Key = Aes128Key>;
68     /// Plain AES-256 implementation (without block cipher mode).
69     type Aes256: aes::Aes<Key = Aes256Key>;
70     /// AES-128 with CTR block mode
71     type AesCtr128: aes::ctr::AesCtr<Key = aes::Aes128Key>;
72     /// AES-256 with CTR block mode
73     type AesCtr256: aes::ctr::AesCtr<Key = aes::Aes256Key>;
74     /// The trait defining ed25519, a Edwards-curve Digital Signature Algorithm signature scheme
75     /// using SHA-512 (SHA-2) and Curve25519
76     type Ed25519: ed25519::Ed25519Provider;
77 
78     /// The cryptographically secure random number generator
79     type CryptoRng: CryptoRng;
80 
81     /// Compares the two given slices, in constant time, and returns true if they are equal.
constant_time_eq(a: &[u8], b: &[u8]) -> bool82     fn constant_time_eq(a: &[u8], b: &[u8]) -> bool;
83 }
84 
85 /// Wrapper to a cryptographically secure pseudo random number generator
86 pub trait CryptoRng {
87     /// Returns an instance of the rng
new() -> Self88     fn new() -> Self;
89 
90     /// Return the next random u64
next_u64(&mut self) -> u6491     fn next_u64(&mut self) -> u64;
92 
93     /// Fill dest with random data
fill(&mut self, dest: &mut [u8])94     fn fill(&mut self, dest: &mut [u8]);
95 
96     /// Generate a random byte
gen<U8>(&mut self) -> u897     fn gen<U8>(&mut self) -> u8 {
98         let mut arr = [0u8; 1];
99         self.fill(&mut arr);
100         arr[0]
101     }
102 }
103 
104 /// If impls want to opt out of passing a Rng they can simply use `()` for the Rng associated type
105 impl CryptoRng for () {
new() -> Self106     fn new() -> Self {}
107 
next_u64(&mut self) -> u64108     fn next_u64(&mut self) -> u64 {
109         unimplemented!()
110     }
111 
fill(&mut self, _dest: &mut [u8])112     fn fill(&mut self, _dest: &mut [u8]) {
113         unimplemented!()
114     }
115 }
116 
117 use crate::aes::{Aes128Key, Aes256Key};
118 #[cfg(feature = "testing")]
119 pub use rstest_reuse;
120 
121 /// Utilities for testing implementations of this crate.
122 #[cfg(feature = "testing")]
123 pub mod testing {
124     extern crate alloc;
125     use crate::CryptoProvider;
126     use alloc::{format, string::String};
127     use core::marker::PhantomData;
128     use hex_literal::hex;
129     use rand::{Rng, RngCore};
130     use rstest_reuse::template;
131 
132     /// Common items that needs to be imported to use these test cases
133     pub mod prelude {
134         pub use super::CryptoProviderTestCase;
135         pub use rstest::rstest;
136         pub use rstest_reuse;
137         pub use rstest_reuse::apply;
138     }
139 
140     /// A test case for Crypto Provider. A test case is a function that panics if the test fails.
141     pub type CryptoProviderTestCase<T> = fn(PhantomData<T>);
142 
143     #[derive(Debug)]
144     pub(crate) struct TestError(String);
145 
146     impl TestError {
new<D: core::fmt::Debug>(value: D) -> Self147         pub(crate) fn new<D: core::fmt::Debug>(value: D) -> Self {
148             Self(format!("{value:?}"))
149         }
150     }
151 
152     /// Test for `constant_time_eq` when the two inputs are equal.
constant_time_eq_test_equal<C: CryptoProvider>(_marker: PhantomData<C>)153     pub fn constant_time_eq_test_equal<C: CryptoProvider>(_marker: PhantomData<C>) {
154         assert!(C::constant_time_eq(
155             &hex!("00010203040506070809"),
156             &hex!("00010203040506070809")
157         ));
158     }
159 
160     /// Test for `constant_time_eq` when the two inputs are not equal.
constant_time_eq_test_not_equal<C: CryptoProvider>(_marker: PhantomData<C>)161     pub fn constant_time_eq_test_not_equal<C: CryptoProvider>(_marker: PhantomData<C>) {
162         assert!(!C::constant_time_eq(
163             &hex!("00010203040506070809"),
164             &hex!("00000000000000000000")
165         ));
166     }
167 
168     /// Random tests for `constant_time_eq`.
constant_time_eq_random_test<C: CryptoProvider>(_marker: PhantomData<C>)169     pub fn constant_time_eq_random_test<C: CryptoProvider>(_marker: PhantomData<C>) {
170         let mut rng = rand::thread_rng();
171         for _ in 1..100 {
172             // Test using "oracle" of ==, with possibly different lengths for a and b
173             let mut a = alloc::vec![0; rng.gen_range(1..1000)];
174             rng.fill_bytes(&mut a);
175             let mut b = alloc::vec![0; rng.gen_range(1..1000)];
176             rng.fill_bytes(&mut b);
177             assert_eq!(C::constant_time_eq(&a, &b), a == b);
178         }
179 
180         for _ in 1..10000 {
181             // Test using "oracle" of ==, with same lengths for a and b
182             let len = rng.gen_range(1..1000);
183             let mut a = alloc::vec![0; len];
184             rng.fill_bytes(&mut a);
185             let mut b = alloc::vec![0; len];
186             rng.fill_bytes(&mut b);
187             assert_eq!(C::constant_time_eq(&a, &b), a == b);
188         }
189 
190         for _ in 1..10000 {
191             // Clones and the original should always be equal
192             let mut a = alloc::vec![0; rng.gen_range(1..1000)];
193             rng.fill_bytes(&mut a);
194             assert!(C::constant_time_eq(&a, &a.clone()));
195         }
196     }
197 
198     /// Generates the test cases to validate the P256 implementation.
199     /// For example, to test `MyCryptoProvider`:
200     ///
201     /// ```
202     /// use crypto_provider::p256::testing::*;
203     ///
204     /// mod tests {
205     ///     #[apply(constant_time_eq_test_cases)]
206     ///     fn constant_time_eq_tests(
207     ///             testcase: CryptoProviderTestCase<MyCryptoProvider>) {
208     ///         testcase(PhantomData);
209     ///     }
210     /// }
211     /// ```
212     #[template]
213     #[export]
214     #[rstest]
215     #[case::constant_time_eq_test_not_equal(constant_time_eq_test_not_equal)]
216     #[case::constant_time_eq_test_equal(constant_time_eq_test_equal)]
217     #[case::constant_time_eq_random_test(constant_time_eq_random_test)]
constant_time_eq_test_cases<C: CryptoProvider>(#[case] testcase: CryptoProviderTestCase<C>)218     fn constant_time_eq_test_cases<C: CryptoProvider>(#[case] testcase: CryptoProviderTestCase<C>) {
219     }
220 }
221