ring_compat/
aead.rs

1//! Authenticated Encryption with Associated Data Algorithms: AES-GCM, ChaCha20Poly1305
2
3pub use aead::{AeadCore, AeadInPlace, Buffer, Error, KeyInit, KeySizeUser};
4
5#[cfg(feature = "alloc")]
6pub use aead::{Aead, Payload};
7
8use aead::{
9    consts::{U0, U12, U16, U32},
10    generic_array::GenericArray,
11};
12use ring::aead::{
13    Aad, LessSafeKey as Key, Nonce, UnboundKey, AES_128_GCM, AES_256_GCM, CHACHA20_POLY1305,
14};
15
16/// Authentication tags
17pub type Tag = GenericArray<u8, U16>;
18
19/// AES-GCM with a 128-bit key
20pub struct Aes128Gcm(Cipher);
21
22/// AES-GCM with a 256-bit key
23pub struct Aes256Gcm(Cipher);
24
25/// ChaCha20Poly1305
26pub struct ChaCha20Poly1305(Cipher);
27
28macro_rules! impl_aead {
29    ($cipher:ty, $algorithm:expr, $key_size:ty) => {
30        impl KeySizeUser for $cipher {
31            type KeySize = $key_size;
32        }
33
34        impl KeyInit for $cipher {
35            fn new(key: &GenericArray<u8, Self::KeySize>) -> Self {
36                let key = UnboundKey::new(&$algorithm, key.as_slice()).unwrap();
37                Self(Cipher::new(key))
38            }
39        }
40
41        impl AeadCore for $cipher {
42            type NonceSize = U12;
43            type TagSize = U16;
44            type CiphertextOverhead = U0;
45        }
46
47        impl AeadInPlace for $cipher {
48            fn encrypt_in_place_detached(
49                &self,
50                nonce: &GenericArray<u8, Self::NonceSize>,
51                associated_data: &[u8],
52                buffer: &mut [u8],
53            ) -> Result<Tag, Error> {
54                self.0
55                    .encrypt_in_place_detached(nonce.as_slice(), associated_data, buffer)
56            }
57
58            fn decrypt_in_place(
59                &self,
60                nonce: &GenericArray<u8, Self::NonceSize>,
61                associated_data: &[u8],
62                buffer: &mut dyn Buffer,
63            ) -> Result<(), Error> {
64                self.0
65                    .decrypt_in_place(nonce.as_slice(), associated_data, buffer)
66            }
67
68            fn decrypt_in_place_detached(
69                &self,
70                _nonce: &GenericArray<u8, Self::NonceSize>,
71                _associated_data: &[u8],
72                _buffer: &mut [u8],
73                _tag: &Tag,
74            ) -> Result<(), Error> {
75                unimplemented!(); // ring does not allow us to implement this API
76            }
77        }
78    };
79}
80
81impl_aead!(Aes128Gcm, AES_128_GCM, U16);
82impl_aead!(Aes256Gcm, AES_256_GCM, U32);
83impl_aead!(ChaCha20Poly1305, CHACHA20_POLY1305, U32);
84
85/// Generic AEAD cipher support
86pub(crate) struct Cipher(Key);
87
88impl Cipher {
89    /// Instantiate a particular AEAD algorithm
90    pub fn new(key: UnboundKey) -> Self {
91        Cipher(Key::new(key))
92    }
93
94    /// Encrypt the ciphertext in place, returning a tag
95    fn encrypt_in_place_detached(
96        &self,
97        nonce: &[u8],
98        associated_data: &[u8],
99        buffer: &mut [u8],
100    ) -> Result<Tag, Error> {
101        self.0
102            .seal_in_place_separate_tag(
103                Nonce::try_assume_unique_for_key(nonce).map_err(|_| Error)?,
104                Aad::from(associated_data),
105                buffer,
106            )
107            .map(|tag| Tag::clone_from_slice(tag.as_ref()))
108            .map_err(|_| Error)
109    }
110
111    fn decrypt_in_place(
112        &self,
113        nonce: &[u8],
114        associated_data: &[u8],
115        buffer: &mut dyn Buffer,
116    ) -> Result<(), Error> {
117        let pt_len = self
118            .0
119            .open_in_place(
120                Nonce::try_assume_unique_for_key(nonce).map_err(|_| Error)?,
121                Aad::from(associated_data),
122                buffer.as_mut(),
123            )
124            .map_err(|_| Error)?
125            .len();
126
127        buffer.truncate(pt_len);
128        Ok(())
129    }
130}