crypto/ciphers/
traits.rs

1// Copyright 2020 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4use core::num::NonZeroUsize;
5
6use generic_array::{typenum::Unsigned, ArrayLength, GenericArray};
7
8pub mod consts {
9    pub use generic_array::typenum::*;
10}
11
12/// A key used by an [`Aead`] implementation.
13pub type Key<T> = GenericArray<u8, <T as Aead>::KeyLength>;
14
15/// A nonce used by an [`Aead`] implementation.
16pub type Nonce<T> = GenericArray<u8, <T as Aead>::NonceLength>;
17
18/// A tag produced by an [`Aead`] implementation.
19pub type Tag<T> = GenericArray<u8, <T as Aead>::TagLength>;
20
21/// A common interface for AEAD encryption algorithms.
22///
23/// Example using [`Aes256Gcm`][`crate::ciphers::aes::Aes256Gcm`]:
24///
25/// ```rust
26/// #[cfg(all(feature = "random", feature = "aes-gcm", feature = "std"))]
27/// {
28///     use crypto::ciphers::{
29///         aes_gcm::Aes256Gcm,
30///         traits::{Aead, Key, Nonce, Tag},
31///     };
32///     let plaintext: &[u8] = b"crypto.rs";
33///     let associated_data: &[u8] = b"stronghold";
34///     let mut encrypted: Vec<u8> = vec![0; plaintext.len()];
35///     let mut decrypted: Vec<u8> = vec![0; encrypted.len()];
36///     let mut tag: Vec<u8> = vec![0; Aes256Gcm::TAG_LENGTH];
37///
38///     let key: Key<Aes256Gcm> = Default::default();
39///     let nonce: Nonce<Aes256Gcm> = Aes256Gcm::random_nonce()?;
40///
41///     Aes256Gcm::try_encrypt(
42///         &key,
43///         &nonce,
44///         associated_data,
45///         plaintext,
46///         &mut encrypted,
47///         &mut tag,
48///     )?;
49///
50///     Aes256Gcm::try_decrypt(
51///         &key,
52///         &nonce,
53///         associated_data,
54///         &mut decrypted,
55///         &encrypted,
56///         &tag,
57///     )?;
58///
59///     assert_eq!(decrypted, plaintext);
60///
61///     Ok::<(), crypto::Error>(())
62/// }
63/// #[cfg(not(all(feature = "random", feature = "aes-gcm", feature = "std")))]
64/// Ok::<(), crypto::Error>(())
65/// ```
66pub trait Aead {
67    /// The size of the [`key`][`Key`] required by this algorithm.
68    type KeyLength: ArrayLength<u8>;
69
70    /// The size of the [`nonce`][`Nonce`] required by this algorithm.
71    type NonceLength: ArrayLength<u8>;
72
73    /// The size of the [`tag`][`Tag`] produced by this algorithm.
74    type TagLength: ArrayLength<u8>;
75
76    /// A human-friendly identifier of this algorithm.
77    const NAME: &'static str;
78
79    /// A const version of [`Aead::KeyLength`].
80    const KEY_LENGTH: usize = <Self::KeyLength as Unsigned>::USIZE;
81
82    /// A const version of [`Aead::NonceLength`].
83    const NONCE_LENGTH: usize = <Self::NonceLength as Unsigned>::USIZE;
84
85    /// A const version of [`Aead::TagLength`].
86    const TAG_LENGTH: usize = <Self::TagLength as Unsigned>::USIZE;
87
88    /// Encrypt the given `plaintext` using `key` and return the length of `ciphertext`.
89    ///
90    /// The output is written to the `ciphertext`/`tag` buffers.
91    fn encrypt(
92        key: &Key<Self>,
93        nonce: &Nonce<Self>,
94        associated_data: &[u8],
95        plaintext: &[u8],
96        ciphertext: &mut [u8],
97        tag: &mut Tag<Self>,
98    ) -> crate::Result<usize>;
99
100    /// Decrypt the given `ciphertext` using `key` and `tag` and return the length of `plaintext`.
101    ///
102    /// The output is written to the `plaintext` buffer.
103    fn decrypt(
104        key: &Key<Self>,
105        nonce: &Nonce<Self>,
106        associated_data: &[u8],
107        plaintext: &mut [u8],
108        ciphertext: &[u8],
109        tag: &Tag<Self>,
110    ) -> crate::Result<usize>;
111
112    /// Encrypt the given `plaintext` using `key` and return the length of `ciphertext`.
113    ///
114    /// The output is written to `ciphertext`.
115    ///
116    /// This is a version of [`Aead::encrypt`] with easier-to-use parameters.
117    fn try_encrypt(
118        key: &[u8],
119        nonce: &[u8],
120        associated_data: &[u8],
121        plaintext: &[u8],
122        ciphertext: &mut [u8],
123        tag: &mut [u8],
124    ) -> crate::Result<usize> {
125        let key: &Key<Self> = try_generic_array(key, "key")?;
126        let nonce: &Nonce<Self> = try_generic_array(nonce, "nonce")?;
127
128        let tag: &mut Tag<Self> = try_generic_array_mut(tag, "tag")?;
129
130        Self::encrypt(key, nonce, associated_data, plaintext, ciphertext, tag)
131    }
132
133    /// Decrypt the given `ciphertext` using `key` and `tag` and return the length of `plaintext`.
134    ///
135    /// The output is written to the `plaintext` buffer.
136    ///
137    /// This is a version of [`Aead::decrypt`] with easier-to-use parameters.
138    fn try_decrypt(
139        key: &[u8],
140        nonce: &[u8],
141        associated_data: &[u8],
142        plaintext: &mut [u8],
143        ciphertext: &[u8],
144        tag: &[u8],
145    ) -> crate::Result<usize> {
146        let key: &Key<Self> = try_generic_array(key, "key")?;
147        let nonce: &Nonce<Self> = try_generic_array(nonce, "nonce")?;
148        let tag: &Tag<Self> = try_generic_array(tag, "tag")?;
149
150        Self::decrypt(key, nonce, associated_data, plaintext, ciphertext, tag)
151    }
152
153    /// Generates a random nonce with the correct size for this algorithm.
154    #[cfg(feature = "random")]
155    fn random_nonce() -> crate::Result<Nonce<Self>> {
156        let mut nonce: Nonce<Self> = Default::default();
157
158        crate::utils::rand::fill(&mut nonce)?;
159
160        Ok(nonce)
161    }
162
163    /// Returns the size of the padding applied to the input buffer.
164    ///
165    /// Note: This is not applicable to all implementations.
166    fn padsize(_: &[u8]) -> Option<NonZeroUsize> {
167        None
168    }
169}
170
171#[inline(always)]
172fn try_generic_array<'a, T>(slice: &'a [u8], name: &'static str) -> crate::Result<&'a GenericArray<u8, T>>
173where
174    T: ArrayLength<u8>,
175{
176    if slice.len() == T::USIZE {
177        Ok(slice.into())
178    } else {
179        Err(crate::Error::BufferSize {
180            name,
181            needs: T::USIZE,
182            has: slice.len(),
183        })
184    }
185}
186
187#[inline(always)]
188fn try_generic_array_mut<'a, T>(slice: &'a mut [u8], name: &'static str) -> crate::Result<&'a mut GenericArray<u8, T>>
189where
190    T: ArrayLength<u8>,
191{
192    if slice.len() == T::USIZE {
193        Ok(slice.into())
194    } else {
195        Err(crate::Error::BufferSize {
196            name,
197            needs: T::USIZE,
198            has: slice.len(),
199        })
200    }
201}