embedded_cal/aead.rs
1// SPDX-License-Identifier: MIT OR Apache-2.0
2// SPDX-FileCopyrightText: Inria-AIO, Cryspen, and Christian Amsüss
3
4// FIXME: Document that we don't do variable length tags (or more precisely, overhead of encryption
5// like in plain AES), and that we expect the tag to be separate (although we could consider
6// changing interfaces if it turns out that everyone appends the tag to the ciphertext anyway, to
7// the point where it's easier to just take a longe buffer, especially if future algorithms start
8// *expecing* that).
9
10/// Symmetric encryption with authentication and additional data.
11///
12/// This trait is modelled after the
13/// [`aead::AeadInPlace`](https://docs.rs/aead/latest/aead/trait.AeadInPlace.html) trait,
14/// but does not use it directly because
15/// - `embedded-cal` passes around an exclusive reference to its engine, and
16/// - its operation is cryptographically agile rather than monomorphized over algorithms.
17pub trait AeadProvider {
18 type Algorithm: AeadAlgorithm;
19 type Key: Sized;
20 type Tag: Sized + AsRef<[u8]>;
21
22 /// Loads a key from the key's bytes.
23 ///
24 /// # Panics
25 ///
26 /// … if key's length is not `alg.key_length()`.
27 fn load_from_keydata(&mut self, alg: Self::Algorithm, key: &[u8]) -> Self::Key;
28
29 /// Encrypts data in place.
30 ///
31 /// The AEAD tag is returned separately; depending on the higher-layer protocol it is appended
32 /// to the message or gets sent separately.
33 ///
34 /// # Panics
35 ///
36 /// … if nonce's length is not `alg.nonce_length()` of the algorithm that generated the key.
37 // Potential for enhancement: Create a key-and-nonce type that moves the nonce length check
38 // from encryption time to preparation time?
39 fn encrypt_in_place(
40 &mut self,
41 key: &Self::Key,
42 nonce: &[u8],
43 message: &mut [u8],
44 aad: impl AadGenerator,
45 ) -> Self::Tag;
46
47 /// Decrypts data in place.
48 ///
49 /// The AEAD tag is returned separately; depending on the higher-layer protocol it is appended
50 /// to the message or gets sent separately.
51 ///
52 /// # Panics
53 ///
54 /// … if nonce's length is not `alg.nonce_length()` of the algorithm that generated the key, or
55 /// the tag's length is not `alg.tag_length()`.
56 ///
57 /// # Implementation guidance
58 ///
59 /// As the message is passed in in a buffer that is available even in case of error, it is best
60 /// practice to zero the message when verification fails, to make sure that even when the error
61 /// is handled badly, an attacker can not hope to place crafted content in a place that might
62 /// be mistaken for verified data.
63 #[must_use = "message must not be accessed after a failed decryption"]
64 fn decrypt_in_place(
65 &mut self,
66 key: &Self::Key,
67 nonce: &[u8],
68 message: &mut [u8],
69 tag: &[u8],
70 aad: impl AadGenerator,
71 ) -> Result<(), DecryptionFailed>;
72}
73
74/// Error indicating that an AEAD decryption failed.
75///
76/// AEAD algorithms generally do not report structured errors; this always indicates some form of
77/// "the calculated AEAD tag mismatched".
78#[derive(Debug)]
79pub struct DecryptionFailed;
80
81impl core::fmt::Display for DecryptionFailed {
82 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
83 f.write_str("decryption failed")
84 }
85}
86
87impl core::error::Error for DecryptionFailed {}
88
89/// An AEAD algorithm identifier.
90pub trait AeadAlgorithm: Sized + PartialEq + Eq + core::fmt::Debug + Clone {
91 /// Length of a key in bytes.
92 fn key_length(&self) -> usize;
93
94 /// Length of the cryptographic tag in bytes.
95 fn tag_length(&self) -> usize;
96
97 /// Length of the nonce (called IV in some algorithms) in bytes.
98 fn nonce_length(&self) -> usize;
99
100 /// Selects an AEAD algorithm from its COSE number.
101 ///
102 /// The algorithm number comes from the ["COSE Algorithms"
103 /// registry](https://www.iana.org/assignments/cose/cose.xhtml#algorithms) maintained by IANA.
104 #[inline]
105 #[allow(
106 unused_variables,
107 reason = "Argument names are part of the documentation"
108 )]
109 fn from_cose_number(number: impl Into<i128>) -> Option<Self> {
110 None
111 }
112}
113
114/// Tool for providing the AAD (Additional Authenticated Data) in a scatter-gather fashion.
115pub trait AadGenerator {
116 // FIXME: What precise guarantees do we want to ask/give?
117 fn items(&self) -> impl Iterator<Item = &[u8]>;
118}
119
120impl AadGenerator for &[u8] {
121 fn items(&self) -> impl Iterator<Item = &[u8]> {
122 [*self].into_iter()
123 }
124}
125
126impl AadGenerator for &[&[u8]] {
127 fn items(&self) -> impl Iterator<Item = &[u8]> {
128 self.iter().copied()
129 }
130}