xref: /aosp_15_r20/system/security/mls/mls-rs-crypto-boringssl/src/aead.rs (revision e1997b9af69e3155ead6e072d106a0077849ffba)
1*e1997b9aSAndroid Build Coastguard Worker // Copyright 2024, The Android Open Source Project
2*e1997b9aSAndroid Build Coastguard Worker //
3*e1997b9aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*e1997b9aSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*e1997b9aSAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*e1997b9aSAndroid Build Coastguard Worker //
7*e1997b9aSAndroid Build Coastguard Worker //     http://www.apache.org/licenses/LICENSE-2.0
8*e1997b9aSAndroid Build Coastguard Worker //
9*e1997b9aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*e1997b9aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*e1997b9aSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*e1997b9aSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*e1997b9aSAndroid Build Coastguard Worker // limitations under the License.
14*e1997b9aSAndroid Build Coastguard Worker 
15*e1997b9aSAndroid Build Coastguard Worker //! Authenticated encryption with additional data.
16*e1997b9aSAndroid Build Coastguard Worker 
17*e1997b9aSAndroid Build Coastguard Worker use bssl_crypto::aead::{Aead, Aes128Gcm, Aes256Gcm, Chacha20Poly1305};
18*e1997b9aSAndroid Build Coastguard Worker use mls_rs_core::crypto::CipherSuite;
19*e1997b9aSAndroid Build Coastguard Worker use mls_rs_core::error::IntoAnyError;
20*e1997b9aSAndroid Build Coastguard Worker use mls_rs_crypto_traits::{AeadId, AeadType, AES_TAG_LEN};
21*e1997b9aSAndroid Build Coastguard Worker 
22*e1997b9aSAndroid Build Coastguard Worker use core::array::TryFromSliceError;
23*e1997b9aSAndroid Build Coastguard Worker use thiserror::Error;
24*e1997b9aSAndroid Build Coastguard Worker 
25*e1997b9aSAndroid Build Coastguard Worker /// Errors returned from AEAD.
26*e1997b9aSAndroid Build Coastguard Worker #[derive(Debug, Error)]
27*e1997b9aSAndroid Build Coastguard Worker pub enum AeadError {
28*e1997b9aSAndroid Build Coastguard Worker     /// Error returned when conversion from slice to array fails.
29*e1997b9aSAndroid Build Coastguard Worker     #[error(transparent)]
30*e1997b9aSAndroid Build Coastguard Worker     TryFromSliceError(#[from] TryFromSliceError),
31*e1997b9aSAndroid Build Coastguard Worker     /// Error returned when the ciphertext is invalid.
32*e1997b9aSAndroid Build Coastguard Worker     #[error("AEAD ciphertext was invalid")]
33*e1997b9aSAndroid Build Coastguard Worker     InvalidCiphertext,
34*e1997b9aSAndroid Build Coastguard Worker     /// Error returned when the ciphertext length is too short.
35*e1997b9aSAndroid Build Coastguard Worker     #[error("AEAD ciphertext of length {len}, expected length at least {min_len}")]
36*e1997b9aSAndroid Build Coastguard Worker     TooShortCiphertext {
37*e1997b9aSAndroid Build Coastguard Worker         /// Invalid ciphertext length.
38*e1997b9aSAndroid Build Coastguard Worker         len: usize,
39*e1997b9aSAndroid Build Coastguard Worker         /// Minimum ciphertext length.
40*e1997b9aSAndroid Build Coastguard Worker         min_len: usize,
41*e1997b9aSAndroid Build Coastguard Worker     },
42*e1997b9aSAndroid Build Coastguard Worker     /// Error returned when the plaintext is empty.
43*e1997b9aSAndroid Build Coastguard Worker     #[error("message cannot be empty")]
44*e1997b9aSAndroid Build Coastguard Worker     EmptyPlaintext,
45*e1997b9aSAndroid Build Coastguard Worker     /// Error returned when the key length is invalid.
46*e1997b9aSAndroid Build Coastguard Worker     #[error("AEAD key of invalid length {len}, expected length {expected_len}")]
47*e1997b9aSAndroid Build Coastguard Worker     InvalidKeyLen {
48*e1997b9aSAndroid Build Coastguard Worker         /// Invalid key length.
49*e1997b9aSAndroid Build Coastguard Worker         len: usize,
50*e1997b9aSAndroid Build Coastguard Worker         /// Expected key length.
51*e1997b9aSAndroid Build Coastguard Worker         expected_len: usize,
52*e1997b9aSAndroid Build Coastguard Worker     },
53*e1997b9aSAndroid Build Coastguard Worker     /// Error returned when the nonce size is invalid.
54*e1997b9aSAndroid Build Coastguard Worker     #[error("AEAD nonce of invalid length {len}, expected length {expected_len}")]
55*e1997b9aSAndroid Build Coastguard Worker     InvalidNonceLen {
56*e1997b9aSAndroid Build Coastguard Worker         /// Invalid nonce length.
57*e1997b9aSAndroid Build Coastguard Worker         len: usize,
58*e1997b9aSAndroid Build Coastguard Worker         /// Expected nonce length.
59*e1997b9aSAndroid Build Coastguard Worker         expected_len: usize,
60*e1997b9aSAndroid Build Coastguard Worker     },
61*e1997b9aSAndroid Build Coastguard Worker     /// Error returned when unsupported cipher suite is requested.
62*e1997b9aSAndroid Build Coastguard Worker     #[error("unsupported cipher suite")]
63*e1997b9aSAndroid Build Coastguard Worker     UnsupportedCipherSuite,
64*e1997b9aSAndroid Build Coastguard Worker }
65*e1997b9aSAndroid Build Coastguard Worker 
66*e1997b9aSAndroid Build Coastguard Worker impl IntoAnyError for AeadError {
into_dyn_error(self) -> Result<Box<dyn std::error::Error + Send + Sync>, Self>67*e1997b9aSAndroid Build Coastguard Worker     fn into_dyn_error(self) -> Result<Box<dyn std::error::Error + Send + Sync>, Self> {
68*e1997b9aSAndroid Build Coastguard Worker         Ok(self.into())
69*e1997b9aSAndroid Build Coastguard Worker     }
70*e1997b9aSAndroid Build Coastguard Worker }
71*e1997b9aSAndroid Build Coastguard Worker 
72*e1997b9aSAndroid Build Coastguard Worker /// AeadType implementation backed by BoringSSL.
73*e1997b9aSAndroid Build Coastguard Worker #[derive(Clone)]
74*e1997b9aSAndroid Build Coastguard Worker pub struct AeadWrapper(AeadId);
75*e1997b9aSAndroid Build Coastguard Worker 
76*e1997b9aSAndroid Build Coastguard Worker impl AeadWrapper {
77*e1997b9aSAndroid Build Coastguard Worker     /// Creates a new AeadWrapper.
new(cipher_suite: CipherSuite) -> Option<Self>78*e1997b9aSAndroid Build Coastguard Worker     pub fn new(cipher_suite: CipherSuite) -> Option<Self> {
79*e1997b9aSAndroid Build Coastguard Worker         AeadId::new(cipher_suite).map(Self)
80*e1997b9aSAndroid Build Coastguard Worker     }
81*e1997b9aSAndroid Build Coastguard Worker }
82*e1997b9aSAndroid Build Coastguard Worker 
83*e1997b9aSAndroid Build Coastguard Worker #[cfg_attr(not(mls_build_async), maybe_async::must_be_sync)]
84*e1997b9aSAndroid Build Coastguard Worker #[cfg_attr(all(target_arch = "wasm32", mls_build_async), maybe_async::must_be_async(?Send))]
85*e1997b9aSAndroid Build Coastguard Worker #[cfg_attr(all(not(target_arch = "wasm32"), mls_build_async), maybe_async::must_be_async)]
86*e1997b9aSAndroid Build Coastguard Worker impl AeadType for AeadWrapper {
87*e1997b9aSAndroid Build Coastguard Worker     type Error = AeadError;
88*e1997b9aSAndroid Build Coastguard Worker 
seal<'a>( &self, key: &[u8], data: &[u8], aad: Option<&'a [u8]>, nonce: &[u8], ) -> Result<Vec<u8>, AeadError>89*e1997b9aSAndroid Build Coastguard Worker     async fn seal<'a>(
90*e1997b9aSAndroid Build Coastguard Worker         &self,
91*e1997b9aSAndroid Build Coastguard Worker         key: &[u8],
92*e1997b9aSAndroid Build Coastguard Worker         data: &[u8],
93*e1997b9aSAndroid Build Coastguard Worker         aad: Option<&'a [u8]>,
94*e1997b9aSAndroid Build Coastguard Worker         nonce: &[u8],
95*e1997b9aSAndroid Build Coastguard Worker     ) -> Result<Vec<u8>, AeadError> {
96*e1997b9aSAndroid Build Coastguard Worker         if data.is_empty() {
97*e1997b9aSAndroid Build Coastguard Worker             return Err(AeadError::EmptyPlaintext);
98*e1997b9aSAndroid Build Coastguard Worker         }
99*e1997b9aSAndroid Build Coastguard Worker         if key.len() != self.key_size() {
100*e1997b9aSAndroid Build Coastguard Worker             return Err(AeadError::InvalidKeyLen { len: key.len(), expected_len: self.key_size() });
101*e1997b9aSAndroid Build Coastguard Worker         }
102*e1997b9aSAndroid Build Coastguard Worker         if nonce.len() != self.nonce_size() {
103*e1997b9aSAndroid Build Coastguard Worker             return Err(AeadError::InvalidNonceLen {
104*e1997b9aSAndroid Build Coastguard Worker                 len: nonce.len(),
105*e1997b9aSAndroid Build Coastguard Worker                 expected_len: self.nonce_size(),
106*e1997b9aSAndroid Build Coastguard Worker             });
107*e1997b9aSAndroid Build Coastguard Worker         }
108*e1997b9aSAndroid Build Coastguard Worker 
109*e1997b9aSAndroid Build Coastguard Worker         let nonce_array = nonce[..self.nonce_size()].try_into()?;
110*e1997b9aSAndroid Build Coastguard Worker 
111*e1997b9aSAndroid Build Coastguard Worker         match self.0 {
112*e1997b9aSAndroid Build Coastguard Worker             AeadId::Aes128Gcm => {
113*e1997b9aSAndroid Build Coastguard Worker                 let cipher = Aes128Gcm::new(key[..self.key_size()].try_into()?);
114*e1997b9aSAndroid Build Coastguard Worker                 Ok(cipher.seal(nonce_array, data, aad.unwrap_or_default()))
115*e1997b9aSAndroid Build Coastguard Worker             }
116*e1997b9aSAndroid Build Coastguard Worker             AeadId::Aes256Gcm => {
117*e1997b9aSAndroid Build Coastguard Worker                 let cipher = Aes256Gcm::new(key[..self.key_size()].try_into()?);
118*e1997b9aSAndroid Build Coastguard Worker                 Ok(cipher.seal(nonce_array, data, aad.unwrap_or_default()))
119*e1997b9aSAndroid Build Coastguard Worker             }
120*e1997b9aSAndroid Build Coastguard Worker             AeadId::Chacha20Poly1305 => {
121*e1997b9aSAndroid Build Coastguard Worker                 let cipher = Chacha20Poly1305::new(key[..self.key_size()].try_into()?);
122*e1997b9aSAndroid Build Coastguard Worker                 Ok(cipher.seal(nonce_array, data, aad.unwrap_or_default()))
123*e1997b9aSAndroid Build Coastguard Worker             }
124*e1997b9aSAndroid Build Coastguard Worker             _ => Err(AeadError::UnsupportedCipherSuite),
125*e1997b9aSAndroid Build Coastguard Worker         }
126*e1997b9aSAndroid Build Coastguard Worker     }
127*e1997b9aSAndroid Build Coastguard Worker 
open<'a>( &self, key: &[u8], ciphertext: &[u8], aad: Option<&'a [u8]>, nonce: &[u8], ) -> Result<Vec<u8>, AeadError>128*e1997b9aSAndroid Build Coastguard Worker     async fn open<'a>(
129*e1997b9aSAndroid Build Coastguard Worker         &self,
130*e1997b9aSAndroid Build Coastguard Worker         key: &[u8],
131*e1997b9aSAndroid Build Coastguard Worker         ciphertext: &[u8],
132*e1997b9aSAndroid Build Coastguard Worker         aad: Option<&'a [u8]>,
133*e1997b9aSAndroid Build Coastguard Worker         nonce: &[u8],
134*e1997b9aSAndroid Build Coastguard Worker     ) -> Result<Vec<u8>, AeadError> {
135*e1997b9aSAndroid Build Coastguard Worker         if ciphertext.len() < AES_TAG_LEN {
136*e1997b9aSAndroid Build Coastguard Worker             return Err(AeadError::TooShortCiphertext {
137*e1997b9aSAndroid Build Coastguard Worker                 len: ciphertext.len(),
138*e1997b9aSAndroid Build Coastguard Worker                 min_len: AES_TAG_LEN,
139*e1997b9aSAndroid Build Coastguard Worker             });
140*e1997b9aSAndroid Build Coastguard Worker         }
141*e1997b9aSAndroid Build Coastguard Worker         if key.len() != self.key_size() {
142*e1997b9aSAndroid Build Coastguard Worker             return Err(AeadError::InvalidKeyLen { len: key.len(), expected_len: self.key_size() });
143*e1997b9aSAndroid Build Coastguard Worker         }
144*e1997b9aSAndroid Build Coastguard Worker         if nonce.len() != self.nonce_size() {
145*e1997b9aSAndroid Build Coastguard Worker             return Err(AeadError::InvalidNonceLen {
146*e1997b9aSAndroid Build Coastguard Worker                 len: nonce.len(),
147*e1997b9aSAndroid Build Coastguard Worker                 expected_len: self.nonce_size(),
148*e1997b9aSAndroid Build Coastguard Worker             });
149*e1997b9aSAndroid Build Coastguard Worker         }
150*e1997b9aSAndroid Build Coastguard Worker 
151*e1997b9aSAndroid Build Coastguard Worker         let nonce_array = nonce[..self.nonce_size()].try_into()?;
152*e1997b9aSAndroid Build Coastguard Worker 
153*e1997b9aSAndroid Build Coastguard Worker         match self.0 {
154*e1997b9aSAndroid Build Coastguard Worker             AeadId::Aes128Gcm => {
155*e1997b9aSAndroid Build Coastguard Worker                 let cipher = Aes128Gcm::new(key[..self.key_size()].try_into()?);
156*e1997b9aSAndroid Build Coastguard Worker                 cipher
157*e1997b9aSAndroid Build Coastguard Worker                     .open(nonce_array, ciphertext, aad.unwrap_or_default())
158*e1997b9aSAndroid Build Coastguard Worker                     .ok_or(AeadError::InvalidCiphertext)
159*e1997b9aSAndroid Build Coastguard Worker             }
160*e1997b9aSAndroid Build Coastguard Worker             AeadId::Aes256Gcm => {
161*e1997b9aSAndroid Build Coastguard Worker                 let cipher = Aes256Gcm::new(key[..self.key_size()].try_into()?);
162*e1997b9aSAndroid Build Coastguard Worker                 cipher
163*e1997b9aSAndroid Build Coastguard Worker                     .open(nonce_array, ciphertext, aad.unwrap_or_default())
164*e1997b9aSAndroid Build Coastguard Worker                     .ok_or(AeadError::InvalidCiphertext)
165*e1997b9aSAndroid Build Coastguard Worker             }
166*e1997b9aSAndroid Build Coastguard Worker             AeadId::Chacha20Poly1305 => {
167*e1997b9aSAndroid Build Coastguard Worker                 let cipher = Chacha20Poly1305::new(key[..self.key_size()].try_into()?);
168*e1997b9aSAndroid Build Coastguard Worker                 cipher
169*e1997b9aSAndroid Build Coastguard Worker                     .open(nonce_array, ciphertext, aad.unwrap_or_default())
170*e1997b9aSAndroid Build Coastguard Worker                     .ok_or(AeadError::InvalidCiphertext)
171*e1997b9aSAndroid Build Coastguard Worker             }
172*e1997b9aSAndroid Build Coastguard Worker             _ => Err(AeadError::UnsupportedCipherSuite),
173*e1997b9aSAndroid Build Coastguard Worker         }
174*e1997b9aSAndroid Build Coastguard Worker     }
175*e1997b9aSAndroid Build Coastguard Worker 
176*e1997b9aSAndroid Build Coastguard Worker     #[inline(always)]
key_size(&self) -> usize177*e1997b9aSAndroid Build Coastguard Worker     fn key_size(&self) -> usize {
178*e1997b9aSAndroid Build Coastguard Worker         self.0.key_size()
179*e1997b9aSAndroid Build Coastguard Worker     }
180*e1997b9aSAndroid Build Coastguard Worker 
nonce_size(&self) -> usize181*e1997b9aSAndroid Build Coastguard Worker     fn nonce_size(&self) -> usize {
182*e1997b9aSAndroid Build Coastguard Worker         self.0.nonce_size()
183*e1997b9aSAndroid Build Coastguard Worker     }
184*e1997b9aSAndroid Build Coastguard Worker 
aead_id(&self) -> u16185*e1997b9aSAndroid Build Coastguard Worker     fn aead_id(&self) -> u16 {
186*e1997b9aSAndroid Build Coastguard Worker         self.0 as u16
187*e1997b9aSAndroid Build Coastguard Worker     }
188*e1997b9aSAndroid Build Coastguard Worker }
189*e1997b9aSAndroid Build Coastguard Worker 
190*e1997b9aSAndroid Build Coastguard Worker #[cfg(all(not(mls_build_async), test))]
191*e1997b9aSAndroid Build Coastguard Worker mod test {
192*e1997b9aSAndroid Build Coastguard Worker     use super::{AeadError, AeadWrapper};
193*e1997b9aSAndroid Build Coastguard Worker     use assert_matches::assert_matches;
194*e1997b9aSAndroid Build Coastguard Worker     use mls_rs_core::crypto::CipherSuite;
195*e1997b9aSAndroid Build Coastguard Worker     use mls_rs_crypto_traits::{AeadType, AES_TAG_LEN};
196*e1997b9aSAndroid Build Coastguard Worker 
get_aeads() -> Vec<AeadWrapper>197*e1997b9aSAndroid Build Coastguard Worker     fn get_aeads() -> Vec<AeadWrapper> {
198*e1997b9aSAndroid Build Coastguard Worker         [
199*e1997b9aSAndroid Build Coastguard Worker             CipherSuite::CURVE25519_AES128,
200*e1997b9aSAndroid Build Coastguard Worker             CipherSuite::CURVE25519_CHACHA,
201*e1997b9aSAndroid Build Coastguard Worker             CipherSuite::CURVE448_AES256,
202*e1997b9aSAndroid Build Coastguard Worker         ]
203*e1997b9aSAndroid Build Coastguard Worker         .into_iter()
204*e1997b9aSAndroid Build Coastguard Worker         .map(|suite| AeadWrapper::new(suite).unwrap())
205*e1997b9aSAndroid Build Coastguard Worker         .collect()
206*e1997b9aSAndroid Build Coastguard Worker     }
207*e1997b9aSAndroid Build Coastguard Worker 
208*e1997b9aSAndroid Build Coastguard Worker     #[test]
seal_and_open()209*e1997b9aSAndroid Build Coastguard Worker     fn seal_and_open() {
210*e1997b9aSAndroid Build Coastguard Worker         for aead in get_aeads() {
211*e1997b9aSAndroid Build Coastguard Worker             let key = vec![42u8; aead.key_size()];
212*e1997b9aSAndroid Build Coastguard Worker             let nonce = vec![42u8; aead.nonce_size()];
213*e1997b9aSAndroid Build Coastguard Worker             let plaintext = b"message";
214*e1997b9aSAndroid Build Coastguard Worker 
215*e1997b9aSAndroid Build Coastguard Worker             let ciphertext = aead.seal(&key, plaintext, None, &nonce).unwrap();
216*e1997b9aSAndroid Build Coastguard Worker             assert_eq!(
217*e1997b9aSAndroid Build Coastguard Worker                 plaintext,
218*e1997b9aSAndroid Build Coastguard Worker                 aead.open(&key, ciphertext.as_slice(), None, &nonce).unwrap().as_slice(),
219*e1997b9aSAndroid Build Coastguard Worker                 "open failed for AEAD with ID {}",
220*e1997b9aSAndroid Build Coastguard Worker                 aead.aead_id(),
221*e1997b9aSAndroid Build Coastguard Worker             );
222*e1997b9aSAndroid Build Coastguard Worker         }
223*e1997b9aSAndroid Build Coastguard Worker     }
224*e1997b9aSAndroid Build Coastguard Worker 
225*e1997b9aSAndroid Build Coastguard Worker     #[test]
seal_and_open_with_invalid_key()226*e1997b9aSAndroid Build Coastguard Worker     fn seal_and_open_with_invalid_key() {
227*e1997b9aSAndroid Build Coastguard Worker         for aead in get_aeads() {
228*e1997b9aSAndroid Build Coastguard Worker             let data = b"top secret data that's long enough";
229*e1997b9aSAndroid Build Coastguard Worker             let nonce = vec![42u8; aead.nonce_size()];
230*e1997b9aSAndroid Build Coastguard Worker 
231*e1997b9aSAndroid Build Coastguard Worker             let key_short = vec![42u8; aead.key_size() - 1];
232*e1997b9aSAndroid Build Coastguard Worker             assert_matches!(
233*e1997b9aSAndroid Build Coastguard Worker                 aead.seal(&key_short, data, None, &nonce),
234*e1997b9aSAndroid Build Coastguard Worker                 Err(AeadError::InvalidKeyLen { .. }),
235*e1997b9aSAndroid Build Coastguard Worker                 "seal with short key should fail for AEAD with ID {}",
236*e1997b9aSAndroid Build Coastguard Worker                 aead.aead_id(),
237*e1997b9aSAndroid Build Coastguard Worker             );
238*e1997b9aSAndroid Build Coastguard Worker             assert_matches!(
239*e1997b9aSAndroid Build Coastguard Worker                 aead.open(&key_short, data, None, &nonce),
240*e1997b9aSAndroid Build Coastguard Worker                 Err(AeadError::InvalidKeyLen { .. }),
241*e1997b9aSAndroid Build Coastguard Worker                 "open with short key should fail for AEAD with ID {}",
242*e1997b9aSAndroid Build Coastguard Worker                 aead.aead_id(),
243*e1997b9aSAndroid Build Coastguard Worker             );
244*e1997b9aSAndroid Build Coastguard Worker 
245*e1997b9aSAndroid Build Coastguard Worker             let key_long = vec![42u8; aead.key_size() + 1];
246*e1997b9aSAndroid Build Coastguard Worker             assert_matches!(
247*e1997b9aSAndroid Build Coastguard Worker                 aead.seal(&key_long, data, None, &nonce),
248*e1997b9aSAndroid Build Coastguard Worker                 Err(AeadError::InvalidKeyLen { .. }),
249*e1997b9aSAndroid Build Coastguard Worker                 "seal with long key should fail for AEAD with ID {}",
250*e1997b9aSAndroid Build Coastguard Worker                 aead.aead_id(),
251*e1997b9aSAndroid Build Coastguard Worker             );
252*e1997b9aSAndroid Build Coastguard Worker             assert_matches!(
253*e1997b9aSAndroid Build Coastguard Worker                 aead.open(&key_long, data, None, &nonce),
254*e1997b9aSAndroid Build Coastguard Worker                 Err(AeadError::InvalidKeyLen { .. }),
255*e1997b9aSAndroid Build Coastguard Worker                 "open with long key should fail for AEAD with ID {}",
256*e1997b9aSAndroid Build Coastguard Worker                 aead.aead_id(),
257*e1997b9aSAndroid Build Coastguard Worker             );
258*e1997b9aSAndroid Build Coastguard Worker         }
259*e1997b9aSAndroid Build Coastguard Worker     }
260*e1997b9aSAndroid Build Coastguard Worker 
261*e1997b9aSAndroid Build Coastguard Worker     #[test]
invalid_ciphertext()262*e1997b9aSAndroid Build Coastguard Worker     fn invalid_ciphertext() {
263*e1997b9aSAndroid Build Coastguard Worker         for aead in get_aeads() {
264*e1997b9aSAndroid Build Coastguard Worker             let key = vec![42u8; aead.key_size()];
265*e1997b9aSAndroid Build Coastguard Worker             let nonce = vec![42u8; aead.nonce_size()];
266*e1997b9aSAndroid Build Coastguard Worker 
267*e1997b9aSAndroid Build Coastguard Worker             let ciphertext_short = [0u8; AES_TAG_LEN - 1];
268*e1997b9aSAndroid Build Coastguard Worker             assert_matches!(
269*e1997b9aSAndroid Build Coastguard Worker                 aead.open(&key, &ciphertext_short, None, &nonce),
270*e1997b9aSAndroid Build Coastguard Worker                 Err(AeadError::TooShortCiphertext { .. }),
271*e1997b9aSAndroid Build Coastguard Worker                 "open with short ciphertext should fail for AEAD with ID {}",
272*e1997b9aSAndroid Build Coastguard Worker                 aead.aead_id(),
273*e1997b9aSAndroid Build Coastguard Worker             );
274*e1997b9aSAndroid Build Coastguard Worker         }
275*e1997b9aSAndroid Build Coastguard Worker     }
276*e1997b9aSAndroid Build Coastguard Worker 
277*e1997b9aSAndroid Build Coastguard Worker     #[test]
associated_data_mismatch()278*e1997b9aSAndroid Build Coastguard Worker     fn associated_data_mismatch() {
279*e1997b9aSAndroid Build Coastguard Worker         for aead in get_aeads() {
280*e1997b9aSAndroid Build Coastguard Worker             let key = vec![42u8; aead.key_size()];
281*e1997b9aSAndroid Build Coastguard Worker             let nonce = vec![42u8; aead.nonce_size()];
282*e1997b9aSAndroid Build Coastguard Worker 
283*e1997b9aSAndroid Build Coastguard Worker             let ciphertext = aead.seal(&key, b"message", Some(b"foo"), &nonce).unwrap();
284*e1997b9aSAndroid Build Coastguard Worker             assert_matches!(
285*e1997b9aSAndroid Build Coastguard Worker                 aead.open(&key, &ciphertext, Some(b"bar"), &nonce),
286*e1997b9aSAndroid Build Coastguard Worker                 Err(AeadError::InvalidCiphertext),
287*e1997b9aSAndroid Build Coastguard Worker                 "open with incorrect associated data should fail for AEAD with ID {}",
288*e1997b9aSAndroid Build Coastguard Worker                 aead.aead_id(),
289*e1997b9aSAndroid Build Coastguard Worker             );
290*e1997b9aSAndroid Build Coastguard Worker             assert_matches!(
291*e1997b9aSAndroid Build Coastguard Worker                 aead.open(&key, &ciphertext, None, &nonce),
292*e1997b9aSAndroid Build Coastguard Worker                 Err(AeadError::InvalidCiphertext),
293*e1997b9aSAndroid Build Coastguard Worker                 "open with incorrect associated data should fail for AEAD with ID {}",
294*e1997b9aSAndroid Build Coastguard Worker                 aead.aead_id(),
295*e1997b9aSAndroid Build Coastguard Worker             );
296*e1997b9aSAndroid Build Coastguard Worker         }
297*e1997b9aSAndroid Build Coastguard Worker     }
298*e1997b9aSAndroid Build Coastguard Worker 
299*e1997b9aSAndroid Build Coastguard Worker     #[test]
invalid_nonce()300*e1997b9aSAndroid Build Coastguard Worker     fn invalid_nonce() {
301*e1997b9aSAndroid Build Coastguard Worker         for aead in get_aeads() {
302*e1997b9aSAndroid Build Coastguard Worker             let key = vec![42u8; aead.key_size()];
303*e1997b9aSAndroid Build Coastguard Worker             let data = b"top secret data that's long enough";
304*e1997b9aSAndroid Build Coastguard Worker 
305*e1997b9aSAndroid Build Coastguard Worker             let nonce_short = vec![42u8; aead.nonce_size() - 1];
306*e1997b9aSAndroid Build Coastguard Worker             assert_matches!(
307*e1997b9aSAndroid Build Coastguard Worker                 aead.seal(&key, data, None, &nonce_short),
308*e1997b9aSAndroid Build Coastguard Worker                 Err(AeadError::InvalidNonceLen { .. }),
309*e1997b9aSAndroid Build Coastguard Worker                 "seal with short nonce should fail for AEAD with ID {}",
310*e1997b9aSAndroid Build Coastguard Worker                 aead.aead_id(),
311*e1997b9aSAndroid Build Coastguard Worker             );
312*e1997b9aSAndroid Build Coastguard Worker             assert_matches!(
313*e1997b9aSAndroid Build Coastguard Worker                 aead.open(&key, data, None, &nonce_short),
314*e1997b9aSAndroid Build Coastguard Worker                 Err(AeadError::InvalidNonceLen { .. }),
315*e1997b9aSAndroid Build Coastguard Worker                 "open with short nonce should fail for AEAD with ID {}",
316*e1997b9aSAndroid Build Coastguard Worker                 aead.aead_id(),
317*e1997b9aSAndroid Build Coastguard Worker             );
318*e1997b9aSAndroid Build Coastguard Worker 
319*e1997b9aSAndroid Build Coastguard Worker             let nonce_long = vec![42u8; aead.nonce_size() + 1];
320*e1997b9aSAndroid Build Coastguard Worker             assert_matches!(
321*e1997b9aSAndroid Build Coastguard Worker                 aead.seal(&key, data, None, &nonce_long),
322*e1997b9aSAndroid Build Coastguard Worker                 Err(AeadError::InvalidNonceLen { .. }),
323*e1997b9aSAndroid Build Coastguard Worker                 "seal with long nonce should fail for AEAD with ID {}",
324*e1997b9aSAndroid Build Coastguard Worker                 aead.aead_id(),
325*e1997b9aSAndroid Build Coastguard Worker             );
326*e1997b9aSAndroid Build Coastguard Worker             assert_matches!(
327*e1997b9aSAndroid Build Coastguard Worker                 aead.open(&key, data, None, &nonce_long),
328*e1997b9aSAndroid Build Coastguard Worker                 Err(AeadError::InvalidNonceLen { .. }),
329*e1997b9aSAndroid Build Coastguard Worker                 "open with long nonce should fail for AEAD with ID {}",
330*e1997b9aSAndroid Build Coastguard Worker                 aead.aead_id(),
331*e1997b9aSAndroid Build Coastguard Worker             );
332*e1997b9aSAndroid Build Coastguard Worker         }
333*e1997b9aSAndroid Build Coastguard Worker     }
334*e1997b9aSAndroid Build Coastguard Worker }
335