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 //! Traits for AES-GCM-SIV. 16 17 use super::AesKey; 18 extern crate alloc; 19 use alloc::vec::Vec; 20 21 /// An enum for indicating issues with the GCM-SIV encryption/decryption operations. 22 pub enum GcmSivError { 23 /// Returned if the output buffer is too small to store the resulting ciphertext + tag. 24 EncryptOutBufferTooSmall, 25 /// Returned if the ciphertext + tag combination does not match when decrypting a blob. 26 DecryptTagDoesNotMatch, 27 } 28 29 /// An implementation of AES-GCM-SIV. 30 /// 31 /// An AesGcmSiv impl may be used for encryption and decryption. 32 pub trait AesGcmSiv { 33 /// The [AesKey] this cipher uses. See [super::Aes128Key] and [super::Aes256Key] for the common AES-128 and 34 /// AES-256 cases. 35 type Key: AesKey; 36 37 /// Build a `Self` from key material. new(key: &Self::Key) -> Self38 fn new(key: &Self::Key) -> Self; 39 40 /// Encrypt the data in place with a nonce to make sure each ciphertext is unique. 41 /// This will need 16 bytes reserved in the data array for the tag. 42 /// Optionally, additional associated data can be passed in for computation of the cryptographic tag. encrypt(&self, data: &mut Vec<u8>, aad: &[u8], nonce: &[u8]) -> Result<(), GcmSivError>43 fn encrypt(&self, data: &mut Vec<u8>, aad: &[u8], nonce: &[u8]) -> Result<(), GcmSivError>; 44 /// Decrypt the ciphertext concatenated with its tag in place with the nonce used for encryption. 45 /// If associated data was passed in when creating the ciphertext, it should be passed in here as well 46 /// in order to properly decrypt the message. decrypt(&self, data: &mut Vec<u8>, aad: &[u8], nonce: &[u8]) -> Result<(), GcmSivError>47 fn decrypt(&self, data: &mut Vec<u8>, aad: &[u8], nonce: &[u8]) -> Result<(), GcmSivError>; 48 } 49 50 /// Module for testing implementations of this crate. 51 #[cfg(feature = "testing")] 52 pub mod testing { 53 extern crate alloc; 54 55 use alloc::vec::Vec; 56 use core::marker; 57 58 use hex_literal::hex; 59 use rstest_reuse::template; 60 61 use crate::aes::{Aes128Key, Aes256Key}; 62 pub use crate::testing::prelude; 63 64 use super::AesGcmSiv; 65 66 /// Test AES-GCM-SIV-128 encryption/decryption aes_128_gcm_siv_test<A: AesGcmSiv<Key = Aes128Key>>(_marker: marker::PhantomData<A>)67 pub fn aes_128_gcm_siv_test<A: AesGcmSiv<Key = Aes128Key>>(_marker: marker::PhantomData<A>) { 68 // https://github.com/google/wycheproof/blob/master/testvectors/aes_gcm_siv_test.json 69 // TC1 70 let test_key = hex!("01000000000000000000000000000000"); 71 let nonce = hex!("030000000000000000000000"); 72 let aes = A::new(&test_key.into()); 73 let msg = hex!(""); 74 let mut buf = Vec::from(msg.as_slice()); 75 let tag = hex!("dc20e2d83f25705bb49e439eca56de25"); 76 assert!(aes.encrypt(&mut buf, b"", &nonce).is_ok()); 77 assert_eq!(&buf[..], &tag); 78 // TC2 79 let msg = hex!("0100000000000000"); 80 let ct = hex!("b5d839330ac7b786"); 81 let tag = hex!("578782fff6013b815b287c22493a364c"); 82 let mut buf = Vec::from(msg.as_slice()); 83 assert!(aes.encrypt(&mut buf, b"", &nonce).is_ok()); 84 assert_eq!(&buf[..8], &ct); 85 assert_eq!(&buf[8..], &tag); 86 assert!(aes.decrypt(&mut buf, b"", &nonce).is_ok()); 87 assert_eq!(&buf[..], &msg); 88 } 89 90 /// Test AES-256-GCM-SIV encryption/decryption aes_256_gcm_siv_test<A: AesGcmSiv<Key = Aes256Key>>(_marker: marker::PhantomData<A>)91 pub fn aes_256_gcm_siv_test<A: AesGcmSiv<Key = Aes256Key>>(_marker: marker::PhantomData<A>) { 92 // https://github.com/google/wycheproof/blob/master/testvectors/aes_gcm_siv_test.json 93 // TC77 94 let test_key = hex!("0100000000000000000000000000000000000000000000000000000000000000"); 95 let nonce = hex!("030000000000000000000000"); 96 let aes = A::new(&test_key.into()); 97 let msg = hex!("0100000000000000"); 98 let mut buf = Vec::new(); 99 buf.extend_from_slice(&msg); 100 let ct = hex!("c2ef328e5c71c83b"); 101 let tag = hex!("843122130f7364b761e0b97427e3df28"); 102 assert!(aes.encrypt(&mut buf, b"", &nonce).is_ok()); 103 assert_eq!(&buf[..8], &ct); 104 assert_eq!(&buf[8..], &tag); 105 assert!(aes.decrypt(&mut buf, b"", &nonce).is_ok()); 106 assert_eq!(&buf[..], &msg); 107 // TC78 108 let msg = hex!("010000000000000000000000"); 109 let ct = hex!("9aab2aeb3faa0a34aea8e2b1"); 110 let tag = hex!("8ca50da9ae6559e48fd10f6e5c9ca17e"); 111 let mut buf = Vec::from(msg.as_slice()); 112 assert!(aes.encrypt(&mut buf, b"", &nonce).is_ok()); 113 assert_eq!(&buf[..12], &ct); 114 assert_eq!(&buf[12..], &tag); 115 assert!(aes.decrypt(&mut buf, b"", &nonce).is_ok()); 116 assert_eq!(&buf[..], &msg); 117 } 118 119 /// Generates the test cases to validate the AES-128-GCM-SIV implementation. 120 /// For example, to test `MyAesGcmSiv128Impl`: 121 /// 122 /// ``` 123 /// use crypto_provider::aes::gcm_siv::testing::*; 124 /// 125 /// mod tests { 126 /// #[apply(aes_128_gcm_siv_test_cases)] 127 /// fn aes_128_gcm_siv_tests(testcase: CryptoProviderTestCase<MyAesGcmSivImpl>) { 128 /// testcase(MyAesGcmSiv128Impl); 129 /// } 130 /// } 131 /// ``` 132 #[template] 133 #[export] 134 #[rstest] 135 #[case::encrypt(aes_128_gcm_siv_test)] 136 #[case::decrypt(aes_128_gcm_siv_test)] aes_128_gcm_siv_test_cases<F: AesGcmSivFactory<Key = Aes128Key>>( #[case] testcase: CryptoProviderTestCase<F>, )137 fn aes_128_gcm_siv_test_cases<F: AesGcmSivFactory<Key = Aes128Key>>( 138 #[case] testcase: CryptoProviderTestCase<F>, 139 ) { 140 } 141 142 /// Generates the test cases to validate the AES-256-GCM-SIV implementation. 143 /// For example, to test `MyAesGcmSiv256Impl`: 144 /// 145 /// ``` 146 /// use crypto_provider::aes::gcm_siv::testing::*; 147 /// 148 /// mod tests { 149 /// #[apply(aes_256_gcm_siv_test_cases)] 150 /// fn aes_256_gcm_siv_tests(testcase: CryptoProviderTestCase<MyAesGcmSiv256Impl>) { 151 /// testcase(MyAesGcmSiv256Impl); 152 /// } 153 /// } 154 /// ``` 155 #[template] 156 #[export] 157 #[rstest] 158 #[case::encrypt(aes_256_gcm_siv_test)] 159 #[case::decrypt(aes_256_gcm_siv_test)] aes_256_gcm_siv_test_cases<F: AesGcmSivFactory<Key = Aes256Key>>( #[case] testcase: CryptoProviderTestCase<F>, )160 fn aes_256_gcm_siv_test_cases<F: AesGcmSivFactory<Key = Aes256Key>>( 161 #[case] testcase: CryptoProviderTestCase<F>, 162 ) { 163 } 164 } 165