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}