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