1use crate::{
25 cpu, error, hkdf,
26 polyfill::{u64_from_usize, usize_from_u64_saturated},
27};
28use core::ops::RangeFrom;
29
30pub use self::{
31 aes_gcm::{AES_128_GCM, AES_256_GCM},
32 chacha20_poly1305::CHACHA20_POLY1305,
33 less_safe_key::LessSafeKey,
34 nonce::{Nonce, NONCE_LEN},
35 opening_key::OpeningKey,
36 sealing_key::SealingKey,
37 unbound_key::UnboundKey,
38};
39
40pub trait NonceSequence {
50 fn advance(&mut self) -> Result<Nonce, error::Unspecified>;
58}
59
60pub trait BoundKey<N: NonceSequence>: core::fmt::Debug {
62 fn new(key: UnboundKey, nonce_sequence: N) -> Self;
64
65 fn algorithm(&self) -> &'static Algorithm;
67}
68
69#[derive(Clone, Copy)]
75pub struct Aad<A>(A);
76
77impl<A: AsRef<[u8]>> Aad<A> {
78 #[inline]
80 pub fn from(aad: A) -> Self {
81 Self(aad)
82 }
83}
84
85impl<A> AsRef<[u8]> for Aad<A>
86where
87 A: AsRef<[u8]>,
88{
89 fn as_ref(&self) -> &[u8] {
90 self.0.as_ref()
91 }
92}
93
94impl Aad<[u8; 0]> {
95 pub fn empty() -> Self {
97 Self::from([])
98 }
99}
100
101impl<A> core::fmt::Debug for Aad<A>
102where
103 A: core::fmt::Debug,
104{
105 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
106 f.debug_tuple("Aad").field(&self.0).finish()
107 }
108}
109
110impl<A> PartialEq for Aad<A>
111where
112 A: PartialEq,
113{
114 #[inline]
115 fn eq(&self, other: &Self) -> bool {
116 self.0.eq(&other.0)
117 }
118}
119
120impl<A> Eq for Aad<A> where A: Eq {}
121
122#[allow(clippy::large_enum_variant, variant_size_differences)]
123#[derive(Clone)]
124enum KeyInner {
125 AesGcm(aes_gcm::Key),
126 ChaCha20Poly1305(chacha20_poly1305::Key),
127}
128
129impl hkdf::KeyType for &'static Algorithm {
130 #[inline]
131 fn len(&self) -> usize {
132 self.key_len()
133 }
134}
135
136pub struct Algorithm {
138 init: fn(key: &[u8], cpu_features: cpu::Features) -> Result<KeyInner, error::Unspecified>,
139
140 seal: fn(
141 key: &KeyInner,
142 nonce: Nonce,
143 aad: Aad<&[u8]>,
144 in_out: &mut [u8],
145 cpu_features: cpu::Features,
146 ) -> Result<Tag, error::Unspecified>,
147 open: fn(
148 key: &KeyInner,
149 nonce: Nonce,
150 aad: Aad<&[u8]>,
151 in_out: &mut [u8],
152 src: RangeFrom<usize>,
153 cpu_features: cpu::Features,
154 ) -> Result<Tag, error::Unspecified>,
155
156 key_len: usize,
157 id: AlgorithmID,
158}
159
160const fn max_input_len(block_len: usize, overhead_blocks_per_nonce: usize) -> usize {
161 usize_from_u64_saturated(
164 ((1u64 << 32) - u64_from_usize(overhead_blocks_per_nonce)) * u64_from_usize(block_len),
165 )
166}
167
168impl Algorithm {
169 #[inline(always)]
171 pub fn key_len(&self) -> usize {
172 self.key_len
173 }
174
175 #[inline(always)]
179 pub fn tag_len(&self) -> usize {
180 TAG_LEN
181 }
182
183 #[inline(always)]
185 pub fn nonce_len(&self) -> usize {
186 NONCE_LEN
187 }
188}
189
190derive_debug_via_id!(Algorithm);
191
192#[derive(Debug, Eq, PartialEq)]
193enum AlgorithmID {
194 AES_128_GCM,
195 AES_256_GCM,
196 CHACHA20_POLY1305,
197}
198
199impl PartialEq for Algorithm {
200 fn eq(&self, other: &Self) -> bool {
201 self.id == other.id
202 }
203}
204
205impl Eq for Algorithm {}
206
207#[must_use]
209#[repr(C)]
210#[derive(Clone, Copy)]
211pub struct Tag([u8; TAG_LEN]);
212
213impl AsRef<[u8]> for Tag {
214 fn as_ref(&self) -> &[u8] {
215 self.0.as_ref()
216 }
217}
218
219impl TryFrom<&[u8]> for Tag {
220 type Error = error::Unspecified;
221
222 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
223 let raw_tag: [u8; TAG_LEN] = value.try_into().map_err(|_| error::Unspecified)?;
224 Ok(Self::from(raw_tag))
225 }
226}
227
228impl From<[u8; TAG_LEN]> for Tag {
229 #[inline]
230 fn from(value: [u8; TAG_LEN]) -> Self {
231 Self(value)
232 }
233}
234
235const MAX_KEY_LEN: usize = 32;
236
237const TAG_LEN: usize = 16;
239
240pub const MAX_TAG_LEN: usize = TAG_LEN;
242
243mod aes;
244mod aes_gcm;
245mod block;
246mod chacha;
247mod chacha20_poly1305;
248pub mod chacha20_poly1305_openssh;
249mod gcm;
250mod less_safe_key;
251mod nonce;
252mod opening_key;
253mod poly1305;
254pub mod quic;
255mod sealing_key;
256mod shift;
257mod unbound_key;