1 // Copyright 2015-2016 Brian Smith.
2 //
3 // Permission to use, copy, modify, and/or distribute this software for any
4 // purpose with or without fee is hereby granted, provided that the above
5 // copyright notice and this permission notice appear in all copies.
6 //
7 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
8 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
10 // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14
15 //! Authenticated Encryption with Associated Data (AEAD).
16 //!
17 //! See [Authenticated encryption: relations among notions and analysis of the
18 //! generic composition paradigm][AEAD] for an introduction to the concept of
19 //! AEADs.
20 //!
21 //! [AEAD]: http://www-cse.ucsd.edu/~mihir/papers/oem.html
22 //! [`crypto.cipher.AEAD`]: https://golang.org/pkg/crypto/cipher/#AEAD
23
24 use self::block::{Block, BLOCK_LEN};
25 use crate::{constant_time, cpu, error, hkdf, polyfill};
26 use core::ops::RangeFrom;
27
28 pub use self::{
29 aes_gcm::{AES_128_GCM, AES_256_GCM},
30 chacha20_poly1305::CHACHA20_POLY1305,
31 nonce::{Nonce, NONCE_LEN},
32 };
33
34 /// A sequences of unique nonces.
35 ///
36 /// A given `NonceSequence` must never return the same `Nonce` twice from
37 /// `advance()`.
38 ///
39 /// A simple counter is a reasonable (but probably not ideal) `NonceSequence`.
40 ///
41 /// Intentionally not `Clone` or `Copy` since cloning would allow duplication
42 /// of the sequence.
43 pub trait NonceSequence {
44 /// Returns the next nonce in the sequence.
45 ///
46 /// This may fail if "too many" nonces have been requested, where how many
47 /// is too many is up to the implementation of `NonceSequence`. An
48 /// implementation may that enforce a maximum number of records are
49 /// sent/received under a key this way. Once `advance()` fails, it must
50 /// fail for all subsequent calls.
advance(&mut self) -> Result<Nonce, error::Unspecified>51 fn advance(&mut self) -> Result<Nonce, error::Unspecified>;
52 }
53
54 /// An AEAD key bound to a nonce sequence.
55 pub trait BoundKey<N: NonceSequence>: core::fmt::Debug {
56 /// Constructs a new key from the given `UnboundKey` and `NonceSequence`.
new(key: UnboundKey, nonce_sequence: N) -> Self57 fn new(key: UnboundKey, nonce_sequence: N) -> Self;
58
59 /// The key's AEAD algorithm.
algorithm(&self) -> &'static Algorithm60 fn algorithm(&self) -> &'static Algorithm;
61 }
62
63 /// An AEAD key for authenticating and decrypting ("opening"), bound to a nonce
64 /// sequence.
65 ///
66 /// Intentionally not `Clone` or `Copy` since cloning would allow duplication
67 /// of the nonce sequence.
68 pub struct OpeningKey<N: NonceSequence> {
69 key: UnboundKey,
70 nonce_sequence: N,
71 }
72
73 impl<N: NonceSequence> BoundKey<N> for OpeningKey<N> {
new(key: UnboundKey, nonce_sequence: N) -> Self74 fn new(key: UnboundKey, nonce_sequence: N) -> Self {
75 Self {
76 key,
77 nonce_sequence,
78 }
79 }
80
81 #[inline]
algorithm(&self) -> &'static Algorithm82 fn algorithm(&self) -> &'static Algorithm {
83 self.key.algorithm
84 }
85 }
86
87 impl<N: NonceSequence> core::fmt::Debug for OpeningKey<N> {
fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error>88 fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
89 f.debug_struct("OpeningKey")
90 .field("algorithm", &self.algorithm())
91 .finish()
92 }
93 }
94
95 impl<N: NonceSequence> OpeningKey<N> {
96 /// Authenticates and decrypts (“opens”) data in place.
97 ///
98 /// `aad` is the additional authenticated data (AAD), if any.
99 ///
100 /// On input, `in_out` must be the ciphertext followed by the tag. When
101 /// `open_in_place()` returns `Ok(plaintext)`, the input ciphertext
102 /// has been overwritten by the plaintext; `plaintext` will refer to the
103 /// plaintext without the tag.
104 ///
105 /// When `open_in_place()` returns `Err(..)`, `in_out` may have been
106 /// overwritten in an unspecified way.
107 #[inline]
open_in_place<'in_out, A>( &mut self, aad: Aad<A>, in_out: &'in_out mut [u8], ) -> Result<&'in_out mut [u8], error::Unspecified> where A: AsRef<[u8]>,108 pub fn open_in_place<'in_out, A>(
109 &mut self,
110 aad: Aad<A>,
111 in_out: &'in_out mut [u8],
112 ) -> Result<&'in_out mut [u8], error::Unspecified>
113 where
114 A: AsRef<[u8]>,
115 {
116 self.open_within(aad, in_out, 0..)
117 }
118
119 /// Authenticates and decrypts (“opens”) data in place, with a shift.
120 ///
121 /// `aad` is the additional authenticated data (AAD), if any.
122 ///
123 /// On input, `in_out[ciphertext_and_tag]` must be the ciphertext followed
124 /// by the tag. When `open_within()` returns `Ok(plaintext)`, the plaintext
125 /// will be at `in_out[0..plaintext.len()]`. In other words, the following
126 /// two code fragments are equivalent for valid values of
127 /// `ciphertext_and_tag`, except `open_within` will often be more efficient:
128 ///
129 ///
130 /// ```skip
131 /// let plaintext = key.open_within(aad, in_out, cipertext_and_tag)?;
132 /// ```
133 ///
134 /// ```skip
135 /// let ciphertext_and_tag_len = in_out[ciphertext_and_tag].len();
136 /// in_out.copy_within(ciphertext_and_tag, 0);
137 /// let plaintext = key.open_in_place(aad, &mut in_out[..ciphertext_and_tag_len])?;
138 /// ```
139 ///
140 /// Similarly, `key.open_within(aad, in_out, 0..)` is equivalent to
141 /// `key.open_in_place(aad, in_out)`.
142 ///
143 /// When `open_in_place()` returns `Err(..)`, `in_out` may have been
144 /// overwritten in an unspecified way.
145 ///
146 /// The shifting feature is useful in the case where multiple packets are
147 /// being reassembled in place. Consider this example where the peer has
148 /// sent the message “Split stream reassembled in place” split into
149 /// three sealed packets:
150 ///
151 /// ```ascii-art
152 /// Packet 1 Packet 2 Packet 3
153 /// Input: [Header][Ciphertext][Tag][Header][Ciphertext][Tag][Header][Ciphertext][Tag]
154 /// | +--------------+ |
155 /// +------+ +-----+ +----------------------------------+
156 /// v v v
157 /// Output: [Plaintext][Plaintext][Plaintext]
158 /// “Split stream reassembled in place”
159 /// ```
160 ///
161 /// This reassembly be accomplished with three calls to `open_within()`.
162 #[inline]
open_within<'in_out, A>( &mut self, aad: Aad<A>, in_out: &'in_out mut [u8], ciphertext_and_tag: RangeFrom<usize>, ) -> Result<&'in_out mut [u8], error::Unspecified> where A: AsRef<[u8]>,163 pub fn open_within<'in_out, A>(
164 &mut self,
165 aad: Aad<A>,
166 in_out: &'in_out mut [u8],
167 ciphertext_and_tag: RangeFrom<usize>,
168 ) -> Result<&'in_out mut [u8], error::Unspecified>
169 where
170 A: AsRef<[u8]>,
171 {
172 open_within_(
173 &self.key,
174 self.nonce_sequence.advance()?,
175 aad,
176 in_out,
177 ciphertext_and_tag,
178 )
179 }
180 }
181
182 #[inline]
open_within_<'in_out, A: AsRef<[u8]>>( key: &UnboundKey, nonce: Nonce, Aad(aad): Aad<A>, in_out: &'in_out mut [u8], ciphertext_and_tag: RangeFrom<usize>, ) -> Result<&'in_out mut [u8], error::Unspecified>183 fn open_within_<'in_out, A: AsRef<[u8]>>(
184 key: &UnboundKey,
185 nonce: Nonce,
186 Aad(aad): Aad<A>,
187 in_out: &'in_out mut [u8],
188 ciphertext_and_tag: RangeFrom<usize>,
189 ) -> Result<&'in_out mut [u8], error::Unspecified> {
190 fn open_within<'in_out>(
191 key: &UnboundKey,
192 nonce: Nonce,
193 aad: Aad<&[u8]>,
194 in_out: &'in_out mut [u8],
195 ciphertext_and_tag: RangeFrom<usize>,
196 ) -> Result<&'in_out mut [u8], error::Unspecified> {
197 let in_prefix_len = ciphertext_and_tag.start;
198 let ciphertext_and_tag_len = in_out
199 .len()
200 .checked_sub(in_prefix_len)
201 .ok_or(error::Unspecified)?;
202 let ciphertext_len = ciphertext_and_tag_len
203 .checked_sub(TAG_LEN)
204 .ok_or(error::Unspecified)?;
205 check_per_nonce_max_bytes(key.algorithm, ciphertext_len)?;
206 let (in_out, received_tag) = in_out.split_at_mut(in_prefix_len + ciphertext_len);
207 let Tag(calculated_tag) = (key.algorithm.open)(
208 &key.inner,
209 nonce,
210 aad,
211 in_prefix_len,
212 in_out,
213 key.cpu_features,
214 );
215 if constant_time::verify_slices_are_equal(calculated_tag.as_ref(), received_tag).is_err() {
216 // Zero out the plaintext so that it isn't accidentally leaked or used
217 // after verification fails. It would be safest if we could check the
218 // tag before decrypting, but some `open` implementations interleave
219 // authentication with decryption for performance.
220 for b in &mut in_out[..ciphertext_len] {
221 *b = 0;
222 }
223 return Err(error::Unspecified);
224 }
225 // `ciphertext_len` is also the plaintext length.
226 Ok(&mut in_out[..ciphertext_len])
227 }
228
229 open_within(
230 key,
231 nonce,
232 Aad::from(aad.as_ref()),
233 in_out,
234 ciphertext_and_tag,
235 )
236 }
237
238 /// An AEAD key for encrypting and signing ("sealing"), bound to a nonce
239 /// sequence.
240 ///
241 /// Intentionally not `Clone` or `Copy` since cloning would allow duplication
242 /// of the nonce sequence.
243 pub struct SealingKey<N: NonceSequence> {
244 key: UnboundKey,
245 nonce_sequence: N,
246 }
247
248 impl<N: NonceSequence> BoundKey<N> for SealingKey<N> {
new(key: UnboundKey, nonce_sequence: N) -> Self249 fn new(key: UnboundKey, nonce_sequence: N) -> Self {
250 Self {
251 key,
252 nonce_sequence,
253 }
254 }
255
256 #[inline]
algorithm(&self) -> &'static Algorithm257 fn algorithm(&self) -> &'static Algorithm {
258 self.key.algorithm
259 }
260 }
261
262 impl<N: NonceSequence> core::fmt::Debug for SealingKey<N> {
fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error>263 fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
264 f.debug_struct("SealingKey")
265 .field("algorithm", &self.algorithm())
266 .finish()
267 }
268 }
269
270 impl<N: NonceSequence> SealingKey<N> {
271 /// Deprecated. Renamed to `seal_in_place_append_tag()`.
272 #[deprecated(note = "Renamed to `seal_in_place_append_tag`.")]
273 #[inline]
seal_in_place<A, InOut>( &mut self, aad: Aad<A>, in_out: &mut InOut, ) -> Result<(), error::Unspecified> where A: AsRef<[u8]>, InOut: AsMut<[u8]> + for<'in_out> Extend<&'in_out u8>,274 pub fn seal_in_place<A, InOut>(
275 &mut self,
276 aad: Aad<A>,
277 in_out: &mut InOut,
278 ) -> Result<(), error::Unspecified>
279 where
280 A: AsRef<[u8]>,
281 InOut: AsMut<[u8]> + for<'in_out> Extend<&'in_out u8>,
282 {
283 self.seal_in_place_append_tag(aad, in_out)
284 }
285
286 /// Encrypts and signs (“seals”) data in place, appending the tag to the
287 /// resulting ciphertext.
288 ///
289 /// `key.seal_in_place_append_tag(aad, in_out)` is equivalent to:
290 ///
291 /// ```skip
292 /// key.seal_in_place_separate_tag(aad, in_out.as_mut())
293 /// .map(|tag| in_out.extend(tag.as_ref()))
294 /// ```
295 #[inline]
seal_in_place_append_tag<A, InOut>( &mut self, aad: Aad<A>, in_out: &mut InOut, ) -> Result<(), error::Unspecified> where A: AsRef<[u8]>, InOut: AsMut<[u8]> + for<'in_out> Extend<&'in_out u8>,296 pub fn seal_in_place_append_tag<A, InOut>(
297 &mut self,
298 aad: Aad<A>,
299 in_out: &mut InOut,
300 ) -> Result<(), error::Unspecified>
301 where
302 A: AsRef<[u8]>,
303 InOut: AsMut<[u8]> + for<'in_out> Extend<&'in_out u8>,
304 {
305 self.seal_in_place_separate_tag(aad, in_out.as_mut())
306 .map(|tag| in_out.extend(tag.as_ref()))
307 }
308
309 /// Encrypts and signs (“seals”) data in place.
310 ///
311 /// `aad` is the additional authenticated data (AAD), if any. This is
312 /// authenticated but not encrypted. The type `A` could be a byte slice
313 /// `&[u8]`, a byte array `[u8; N]` for some constant `N`, `Vec<u8>`, etc.
314 /// If there is no AAD then use `Aad::empty()`.
315 ///
316 /// The plaintext is given as the input value of `in_out`. `seal_in_place()`
317 /// will overwrite the plaintext with the ciphertext and return the tag.
318 /// For most protocols, the caller must append the tag to the ciphertext.
319 /// The tag will be `self.algorithm.tag_len()` bytes long.
320 #[inline]
seal_in_place_separate_tag<A>( &mut self, aad: Aad<A>, in_out: &mut [u8], ) -> Result<Tag, error::Unspecified> where A: AsRef<[u8]>,321 pub fn seal_in_place_separate_tag<A>(
322 &mut self,
323 aad: Aad<A>,
324 in_out: &mut [u8],
325 ) -> Result<Tag, error::Unspecified>
326 where
327 A: AsRef<[u8]>,
328 {
329 seal_in_place_separate_tag_(
330 &self.key,
331 self.nonce_sequence.advance()?,
332 Aad::from(aad.as_ref()),
333 in_out,
334 )
335 }
336 }
337
338 #[inline]
seal_in_place_separate_tag_( key: &UnboundKey, nonce: Nonce, aad: Aad<&[u8]>, in_out: &mut [u8], ) -> Result<Tag, error::Unspecified>339 fn seal_in_place_separate_tag_(
340 key: &UnboundKey,
341 nonce: Nonce,
342 aad: Aad<&[u8]>,
343 in_out: &mut [u8],
344 ) -> Result<Tag, error::Unspecified> {
345 check_per_nonce_max_bytes(key.algorithm, in_out.len())?;
346 Ok((key.algorithm.seal)(
347 &key.inner,
348 nonce,
349 aad,
350 in_out,
351 key.cpu_features,
352 ))
353 }
354
355 /// The additionally authenticated data (AAD) for an opening or sealing
356 /// operation. This data is authenticated but is **not** encrypted.
357 ///
358 /// The type `A` could be a byte slice `&[u8]`, a byte array `[u8; N]`
359 /// for some constant `N`, `Vec<u8>`, etc.
360 pub struct Aad<A: AsRef<[u8]>>(A);
361
362 impl<A: AsRef<[u8]>> Aad<A> {
363 /// Construct the `Aad` from the given bytes.
364 #[inline]
from(aad: A) -> Self365 pub fn from(aad: A) -> Self {
366 Aad(aad)
367 }
368 }
369
370 impl<A> AsRef<[u8]> for Aad<A>
371 where
372 A: AsRef<[u8]>,
373 {
as_ref(&self) -> &[u8]374 fn as_ref(&self) -> &[u8] {
375 self.0.as_ref()
376 }
377 }
378
379 impl Aad<[u8; 0]> {
380 /// Construct an empty `Aad`.
empty() -> Self381 pub fn empty() -> Self {
382 Self::from([])
383 }
384 }
385
386 /// An AEAD key without a designated role or nonce sequence.
387 pub struct UnboundKey {
388 inner: KeyInner,
389 algorithm: &'static Algorithm,
390 cpu_features: cpu::Features,
391 }
392
393 impl core::fmt::Debug for UnboundKey {
fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error>394 fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
395 f.debug_struct("UnboundKey")
396 .field("algorithm", &self.algorithm)
397 .finish()
398 }
399 }
400
401 #[allow(clippy::large_enum_variant, variant_size_differences)]
402 enum KeyInner {
403 AesGcm(aes_gcm::Key),
404 ChaCha20Poly1305(chacha20_poly1305::Key),
405 }
406
407 impl UnboundKey {
408 /// Constructs an `UnboundKey`.
409 ///
410 /// Fails if `key_bytes.len() != algorithm.key_len()`.
new( algorithm: &'static Algorithm, key_bytes: &[u8], ) -> Result<Self, error::Unspecified>411 pub fn new(
412 algorithm: &'static Algorithm,
413 key_bytes: &[u8],
414 ) -> Result<Self, error::Unspecified> {
415 let cpu_features = cpu::features();
416 Ok(Self {
417 inner: (algorithm.init)(key_bytes, cpu_features)?,
418 algorithm,
419 cpu_features,
420 })
421 }
422
423 /// The key's AEAD algorithm.
424 #[inline]
algorithm(&self) -> &'static Algorithm425 pub fn algorithm(&self) -> &'static Algorithm {
426 self.algorithm
427 }
428 }
429
430 impl From<hkdf::Okm<'_, &'static Algorithm>> for UnboundKey {
from(okm: hkdf::Okm<&'static Algorithm>) -> Self431 fn from(okm: hkdf::Okm<&'static Algorithm>) -> Self {
432 let mut key_bytes = [0; MAX_KEY_LEN];
433 let key_bytes = &mut key_bytes[..okm.len().key_len];
434 let algorithm = *okm.len();
435 okm.fill(key_bytes).unwrap();
436 Self::new(algorithm, key_bytes).unwrap()
437 }
438 }
439
440 impl hkdf::KeyType for &'static Algorithm {
441 #[inline]
len(&self) -> usize442 fn len(&self) -> usize {
443 self.key_len()
444 }
445 }
446
447 /// Immutable keys for use in situations where `OpeningKey`/`SealingKey` and
448 /// `NonceSequence` cannot reasonably be used.
449 ///
450 /// Prefer to use `OpeningKey`/`SealingKey` and `NonceSequence` when practical.
451 pub struct LessSafeKey {
452 key: UnboundKey,
453 }
454
455 impl LessSafeKey {
456 /// Constructs a `LessSafeKey` from an `UnboundKey`.
new(key: UnboundKey) -> Self457 pub fn new(key: UnboundKey) -> Self {
458 Self { key }
459 }
460
461 /// Like [`OpeningKey::open_in_place()`], except it accepts an arbitrary nonce.
462 ///
463 /// `nonce` must be unique for every use of the key to open data.
464 #[inline]
open_in_place<'in_out, A>( &self, nonce: Nonce, aad: Aad<A>, in_out: &'in_out mut [u8], ) -> Result<&'in_out mut [u8], error::Unspecified> where A: AsRef<[u8]>,465 pub fn open_in_place<'in_out, A>(
466 &self,
467 nonce: Nonce,
468 aad: Aad<A>,
469 in_out: &'in_out mut [u8],
470 ) -> Result<&'in_out mut [u8], error::Unspecified>
471 where
472 A: AsRef<[u8]>,
473 {
474 self.open_within(nonce, aad, in_out, 0..)
475 }
476
477 /// Like [`OpeningKey::open_within()`], except it accepts an arbitrary nonce.
478 ///
479 /// `nonce` must be unique for every use of the key to open data.
480 #[inline]
open_within<'in_out, A>( &self, nonce: Nonce, aad: Aad<A>, in_out: &'in_out mut [u8], ciphertext_and_tag: RangeFrom<usize>, ) -> Result<&'in_out mut [u8], error::Unspecified> where A: AsRef<[u8]>,481 pub fn open_within<'in_out, A>(
482 &self,
483 nonce: Nonce,
484 aad: Aad<A>,
485 in_out: &'in_out mut [u8],
486 ciphertext_and_tag: RangeFrom<usize>,
487 ) -> Result<&'in_out mut [u8], error::Unspecified>
488 where
489 A: AsRef<[u8]>,
490 {
491 open_within_(&self.key, nonce, aad, in_out, ciphertext_and_tag)
492 }
493
494 /// Deprecated. Renamed to `seal_in_place_append_tag()`.
495 #[deprecated(note = "Renamed to `seal_in_place_append_tag`.")]
496 #[inline]
seal_in_place<A, InOut>( &self, nonce: Nonce, aad: Aad<A>, in_out: &mut InOut, ) -> Result<(), error::Unspecified> where A: AsRef<[u8]>, InOut: AsMut<[u8]> + for<'in_out> Extend<&'in_out u8>,497 pub fn seal_in_place<A, InOut>(
498 &self,
499 nonce: Nonce,
500 aad: Aad<A>,
501 in_out: &mut InOut,
502 ) -> Result<(), error::Unspecified>
503 where
504 A: AsRef<[u8]>,
505 InOut: AsMut<[u8]> + for<'in_out> Extend<&'in_out u8>,
506 {
507 self.seal_in_place_append_tag(nonce, aad, in_out)
508 }
509
510 /// Like [`SealingKey::seal_in_place_append_tag()`], except it accepts an
511 /// arbitrary nonce.
512 ///
513 /// `nonce` must be unique for every use of the key to seal data.
514 #[inline]
seal_in_place_append_tag<A, InOut>( &self, nonce: Nonce, aad: Aad<A>, in_out: &mut InOut, ) -> Result<(), error::Unspecified> where A: AsRef<[u8]>, InOut: AsMut<[u8]> + for<'in_out> Extend<&'in_out u8>,515 pub fn seal_in_place_append_tag<A, InOut>(
516 &self,
517 nonce: Nonce,
518 aad: Aad<A>,
519 in_out: &mut InOut,
520 ) -> Result<(), error::Unspecified>
521 where
522 A: AsRef<[u8]>,
523 InOut: AsMut<[u8]> + for<'in_out> Extend<&'in_out u8>,
524 {
525 self.seal_in_place_separate_tag(nonce, aad, in_out.as_mut())
526 .map(|tag| in_out.extend(tag.as_ref()))
527 }
528
529 /// Like `SealingKey::seal_in_place_separate_tag()`, except it accepts an
530 /// arbitrary nonce.
531 ///
532 /// `nonce` must be unique for every use of the key to seal data.
533 #[inline]
seal_in_place_separate_tag<A>( &self, nonce: Nonce, aad: Aad<A>, in_out: &mut [u8], ) -> Result<Tag, error::Unspecified> where A: AsRef<[u8]>,534 pub fn seal_in_place_separate_tag<A>(
535 &self,
536 nonce: Nonce,
537 aad: Aad<A>,
538 in_out: &mut [u8],
539 ) -> Result<Tag, error::Unspecified>
540 where
541 A: AsRef<[u8]>,
542 {
543 seal_in_place_separate_tag_(&self.key, nonce, Aad::from(aad.as_ref()), in_out)
544 }
545
546 /// The key's AEAD algorithm.
547 #[inline]
algorithm(&self) -> &'static Algorithm548 pub fn algorithm(&self) -> &'static Algorithm {
549 &self.key.algorithm
550 }
551 }
552
553 impl core::fmt::Debug for LessSafeKey {
fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error>554 fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
555 f.debug_struct("LessSafeKey")
556 .field("algorithm", self.algorithm())
557 .finish()
558 }
559 }
560
561 /// An AEAD Algorithm.
562 pub struct Algorithm {
563 init: fn(key: &[u8], cpu_features: cpu::Features) -> Result<KeyInner, error::Unspecified>,
564
565 seal: fn(
566 key: &KeyInner,
567 nonce: Nonce,
568 aad: Aad<&[u8]>,
569 in_out: &mut [u8],
570 cpu_features: cpu::Features,
571 ) -> Tag,
572 open: fn(
573 key: &KeyInner,
574 nonce: Nonce,
575 aad: Aad<&[u8]>,
576 in_prefix_len: usize,
577 in_out: &mut [u8],
578 cpu_features: cpu::Features,
579 ) -> Tag,
580
581 key_len: usize,
582 id: AlgorithmID,
583
584 /// Use `max_input_len!()` to initialize this.
585 // TODO: Make this `usize`.
586 max_input_len: u64,
587 }
588
max_input_len(block_len: usize, overhead_blocks_per_nonce: usize) -> u64589 const fn max_input_len(block_len: usize, overhead_blocks_per_nonce: usize) -> u64 {
590 // Each of our AEADs use a 32-bit block counter so the maximum is the
591 // largest input that will not overflow the counter.
592 ((1u64 << 32) - polyfill::u64_from_usize(overhead_blocks_per_nonce))
593 * polyfill::u64_from_usize(block_len)
594 }
595
596 impl Algorithm {
597 /// The length of the key.
598 #[inline(always)]
key_len(&self) -> usize599 pub fn key_len(&self) -> usize {
600 self.key_len
601 }
602
603 /// The length of a tag.
604 ///
605 /// See also `MAX_TAG_LEN`.
606 #[inline(always)]
tag_len(&self) -> usize607 pub fn tag_len(&self) -> usize {
608 TAG_LEN
609 }
610
611 /// The length of the nonces.
612 #[inline(always)]
nonce_len(&self) -> usize613 pub fn nonce_len(&self) -> usize {
614 NONCE_LEN
615 }
616 }
617
618 derive_debug_via_id!(Algorithm);
619
620 #[derive(Debug, Eq, PartialEq)]
621 enum AlgorithmID {
622 AES_128_GCM,
623 AES_256_GCM,
624 CHACHA20_POLY1305,
625 }
626
627 impl PartialEq for Algorithm {
eq(&self, other: &Self) -> bool628 fn eq(&self, other: &Self) -> bool {
629 self.id == other.id
630 }
631 }
632
633 impl Eq for Algorithm {}
634
635 /// An authentication tag.
636 #[must_use]
637 #[repr(C)]
638 pub struct Tag([u8; TAG_LEN]);
639
640 impl AsRef<[u8]> for Tag {
as_ref(&self) -> &[u8]641 fn as_ref(&self) -> &[u8] {
642 self.0.as_ref()
643 }
644 }
645
646 const MAX_KEY_LEN: usize = 32;
647
648 // All the AEADs we support use 128-bit tags.
649 const TAG_LEN: usize = BLOCK_LEN;
650
651 /// The maximum length of a tag for the algorithms in this module.
652 pub const MAX_TAG_LEN: usize = TAG_LEN;
653
check_per_nonce_max_bytes(alg: &Algorithm, in_out_len: usize) -> Result<(), error::Unspecified>654 fn check_per_nonce_max_bytes(alg: &Algorithm, in_out_len: usize) -> Result<(), error::Unspecified> {
655 if polyfill::u64_from_usize(in_out_len) > alg.max_input_len {
656 return Err(error::Unspecified);
657 }
658 Ok(())
659 }
660
661 #[derive(Clone, Copy)]
662 enum Direction {
663 Opening { in_prefix_len: usize },
664 Sealing,
665 }
666
667 mod aes;
668 mod aes_gcm;
669 mod block;
670 mod chacha;
671 mod chacha20_poly1305;
672 pub mod chacha20_poly1305_openssh;
673 mod counter;
674 mod gcm;
675 mod iv;
676 mod nonce;
677 mod poly1305;
678 pub mod quic;
679 mod shift;
680