libcrux_traits/aead/
typed_refs.rs

1//! This module contains the trait and related errors for an Authenticated
2//! Encryption with Associated Data (AEAD) scheme that takes array references
3//! as arguments and writes outputs to mutable array references.
4
5use libcrux_secrets::U8;
6
7use super::slice::KeyGenError;
8
9/// Error that can occur during encryption.
10#[derive(Debug, PartialEq, Eq)]
11pub enum EncryptError {
12    /// The ciphertext buffer has the wrong length.
13    WrongCiphertextLength,
14
15    /// The plaintext is too long for this algorithm or implementation.
16    PlaintextTooLong,
17
18    /// The AAD is too long for this algorithm or implementation.
19    AadTooLong,
20
21    /// The key is for the wrong algorithm.
22    WrongKey,
23
24    /// The tag is for the wrong algorithm.
25    WrongTag,
26
27    /// The nonce is for the wrong algorithm.
28    WrongNonce,
29
30    /// An unknown error occurred during encryption.
31    Unknown,
32}
33
34/// Error that can occur during decryption.
35#[derive(Debug, PartialEq, Eq)]
36pub enum DecryptError {
37    /// The authentication tag is invalid; the ciphertext has been tampered with
38    /// or the key/nonce/aad is incorrect.
39    InvalidTag,
40
41    /// The plaintext buffer has the wrong length.
42    WrongPlaintextLength,
43
44    /// The plaintext is too long for this algorithm or implementation.
45    PlaintextTooLong,
46
47    /// The AAD is too long for this algorithm or implementation.
48    AadTooLong,
49
50    /// The key is for the wrong algorithm.
51    WrongKey,
52
53    /// The tag is for the wrong algorithm.
54    WrongTag,
55
56    /// The nonce is for the wrong algorithm.
57    WrongNonce,
58
59    /// An unknown error occurred during decryption.
60    Unknown,
61}
62
63impl From<super::arrayref::EncryptError> for EncryptError {
64    fn from(value: super::arrayref::EncryptError) -> Self {
65        match value {
66            super::arrayref::EncryptError::WrongCiphertextLength => {
67                EncryptError::WrongCiphertextLength
68            }
69            super::arrayref::EncryptError::PlaintextTooLong => EncryptError::PlaintextTooLong,
70            super::arrayref::EncryptError::AadTooLong => EncryptError::AadTooLong,
71            super::arrayref::EncryptError::Unknown => EncryptError::Unknown,
72        }
73    }
74}
75
76impl From<super::arrayref::DecryptError> for DecryptError {
77    fn from(value: super::arrayref::DecryptError) -> Self {
78        match value {
79            super::arrayref::DecryptError::InvalidTag => DecryptError::InvalidTag,
80            super::arrayref::DecryptError::WrongPlaintextLength => {
81                DecryptError::WrongPlaintextLength
82            }
83            super::arrayref::DecryptError::PlaintextTooLong => DecryptError::PlaintextTooLong,
84            super::arrayref::DecryptError::AadTooLong => DecryptError::AadTooLong,
85            super::arrayref::DecryptError::Unknown => DecryptError::Unknown,
86        }
87    }
88}
89
90impl core::fmt::Display for EncryptError {
91    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
92        let text = match self {
93            EncryptError::WrongCiphertextLength => "ciphertext buffer has wrong length",
94            EncryptError::PlaintextTooLong => {
95                "plaintext is too long for algorithm or implementation"
96            }
97            EncryptError::AadTooLong => "aad is too long for algorithm or implementation",
98            EncryptError::Unknown => "an unknown error occurred",
99            EncryptError::WrongKey => "key is for wrong algorithm",
100            EncryptError::WrongTag => "tag is for wrong algorithm",
101            EncryptError::WrongNonce => "nonce is for wrong algorithm",
102        };
103
104        f.write_str(text)
105    }
106}
107
108impl core::fmt::Display for DecryptError {
109    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
110        let text = match self {
111            DecryptError::InvalidTag => "invalid authentication tag",
112            DecryptError::WrongPlaintextLength => "plaintext buffer has wrong length",
113            DecryptError::PlaintextTooLong => {
114                "plaintext is too long for algorithm or implementation"
115            }
116            DecryptError::AadTooLong => "aad is too long for algorithm or implementation",
117            DecryptError::Unknown => "an unknown error occurred",
118            DecryptError::WrongKey => "key is for wrong algorithm",
119            DecryptError::WrongTag => "tag is for wrong algorithm",
120            DecryptError::WrongNonce => "nonce is for wrong algorithm",
121        };
122
123        f.write_str(text)
124    }
125}
126
127// These are the types for the arguments to AEAD. I wonder if it makes sense to do stuff like
128// implementing a random constructor for Nonce for all LEN in 24..64 or so
129//
130// There also is the question whether we want these to be byte-oriented or whether we want to just
131// make these associated types. That would mean that we'd have to define them separately for all
132// implementations.
133
134/// A Key with the given algorithm. The bytes are borrowed. Contains a marker for which
135/// algorithm the key is to be used with.
136#[derive(Clone, Copy)]
137pub struct KeyRef<'a, Algo> {
138    algorithm: Algo,
139    key: &'a [U8],
140}
141
142/// A Key with the given algorithm. The bytes are borrowed mutably. Contains a marker for
143/// which algorithm the key is to be used with.
144pub struct KeyMut<'a, Algo> {
145    algorithm: Algo,
146    key: &'a mut [U8],
147}
148
149/// A tag with the given algorithm. The bytes are borrowed. Contains a marker for which
150/// algorithm the key is to be used with.
151#[derive(Clone, Copy)]
152pub struct TagRef<'a, Algo> {
153    algorithm: Algo,
154    tag: &'a [U8],
155}
156
157/// A mutable tag with the given algorithm. The bytes are borrowed mutably. Contains a marker
158/// for which algorithm the key is to be used with.
159pub struct TagMut<'a, Algo> {
160    algorithm: Algo,
161    tag: &'a mut [U8],
162}
163
164/// A nonce with the given algorithm. The bytes are borrowed. Contains a marker for which
165/// algorithm the key is to be used with.
166#[derive(Clone, Copy)]
167pub struct NonceRef<'a, Algo> {
168    algorithm: Algo,
169    nonce: &'a [U8],
170}
171
172impl<'a, Algo: Aead + core::fmt::Debug> core::fmt::Debug for KeyRef<'a, Algo> {
173    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
174        f.debug_tuple("Key")
175            .field(&self.algorithm)
176            .field(&"***")
177            .finish()
178    }
179}
180
181/// An Authenticated Encryption with Associated Data (AEAD) scheme. This trait
182/// is low-level and is mostly used for implementing other, more usable APIs.
183///
184/// Some implementors of this trait may impose stronger restrictions on the inputs than described
185/// here. Check the documentation of the types implementing this trait to make sure which inputs
186/// are valid.
187pub trait Aead: Copy + PartialEq {
188    /// Returns the length of keys for this algorithm in bytes.
189    fn key_len(&self) -> usize;
190    /// Returns the length of authentication tags for this algorithm in bytes.
191    fn tag_len(&self) -> usize;
192    /// Returns the length of nonces for this algorithm in bytes.
193    fn nonce_len(&self) -> usize;
194
195    /// Generate a new key for this algorithm using the provided randomness.
196    fn keygen<'a>(&self, key: KeyMut<'a, Self>, rand: &[U8]) -> Result<(), KeyGenError>;
197
198    /// Encrypt a plaintext message, producing a ciphertext and an authentication tag.
199    /// The arguments `plaintext` and `ciphertext` must have the same length.
200    fn encrypt<'a>(
201        &self,
202        ciphertext: &mut [u8],
203        tag: TagMut<'a, Self>,
204        key: KeyRef<'a, Self>,
205        nonce: NonceRef<'a, Self>,
206        aad: &[u8],
207        plaintext: &[U8],
208    ) -> Result<(), EncryptError>;
209
210    /// Decrypt a ciphertext, verifying its authenticity.
211    /// The arguments `plaintext` and `ciphertext` must have the same length.
212    fn decrypt<'a>(
213        &self,
214        plaintext: &mut [U8],
215        key: KeyRef<'a, Self>,
216        nonce: NonceRef<'a, Self>,
217        aad: &[u8],
218        ciphertext: &[u8],
219        tag: TagRef<'a, Self>,
220    ) -> Result<(), DecryptError>;
221
222    /// Creates a new key given the algorithm.
223    fn new_key<'a>(self, key: &'a [U8]) -> Result<KeyRef<'a, Self>, WrongLengthError> {
224        KeyRef::new_for_algo(self, key)
225    }
226    /// Creates a new mutable key given the algorithm.
227    fn new_key_mut<'a>(self, key: &'a mut [U8]) -> Result<KeyMut<'a, Self>, WrongLengthError> {
228        KeyMut::new_for_algo(self, key)
229    }
230    /// Creates a new tag given the algorithm.
231    fn new_tag<'a>(self, tag: &'a [U8]) -> Result<TagRef<'a, Self>, WrongLengthError> {
232        TagRef::new_for_algo(self, tag)
233    }
234    /// Creates a new mutable tag given the algorithm.
235    fn new_tag_mut<'a>(self, tag_mut: &'a mut [U8]) -> Result<TagMut<'a, Self>, WrongLengthError> {
236        TagMut::new_for_algo(self, tag_mut)
237    }
238    /// Creates a new nonce given the algorithm.
239    fn new_nonce<'a>(self, nonce: &'a [U8]) -> Result<NonceRef<'a, Self>, WrongLengthError> {
240        NonceRef::new_for_algo(self, nonce)
241    }
242}
243
244impl<
245        const KEY_LEN: usize,
246        const TAG_LEN: usize,
247        const NONCE_LEN: usize,
248        Algo: super::typed_owned::Aead<
249                Key = [U8; KEY_LEN],
250                Tag = [U8; TAG_LEN],
251                Nonce = [U8; NONCE_LEN],
252                Rand = [U8; KEY_LEN],
253            > + Copy
254            + PartialEq,
255    > Aead for Algo
256{
257    fn key_len(&self) -> usize {
258        KEY_LEN
259    }
260
261    fn tag_len(&self) -> usize {
262        TAG_LEN
263    }
264
265    fn nonce_len(&self) -> usize {
266        NONCE_LEN
267    }
268
269    fn keygen<'a>(&self, key: KeyMut<'a, Self>, rand: &[U8]) -> Result<(), KeyGenError> {
270        if rand.len() < KEY_LEN {
271            return Err(KeyGenError::InsufficientRandomness);
272        }
273
274        key.key.copy_from_slice(rand);
275
276        Ok(())
277    }
278
279    fn encrypt<'a>(
280        &self,
281        ciphertext: &mut [u8],
282        mut tag: TagMut<'a, Self>,
283        key: KeyRef<'a, Self>,
284        nonce: NonceRef<'a, Self>,
285        aad: &[u8],
286        plaintext: &[U8],
287    ) -> Result<(), EncryptError> {
288        if key.algo() != self {
289            return Err(EncryptError::WrongKey);
290        }
291        if tag.algo() != self {
292            return Err(EncryptError::WrongTag);
293        }
294        if nonce.algo() != self {
295            return Err(EncryptError::WrongNonce);
296        }
297
298        // now we expect the lengths to be correct, so later mismatches are unknown errors
299        let key: &[U8; KEY_LEN] = key.as_ref().try_into().map_err(|_| EncryptError::Unknown)?;
300
301        let tag_raw: &mut [U8; TAG_LEN] =
302            tag.as_mut().try_into().map_err(|_| EncryptError::Unknown)?;
303
304        let nonce: &[U8; NONCE_LEN] = nonce
305            .as_ref()
306            .try_into()
307            .map_err(|_| EncryptError::Unknown)?;
308
309        <Self as super::typed_owned::Aead>::encrypt(
310            ciphertext,
311            tag_raw.into(),
312            key.into(),
313            nonce.into(),
314            aad,
315            plaintext,
316        )
317        .map_err(EncryptError::from)
318    }
319
320    fn decrypt<'a>(
321        &self,
322        plaintext: &mut [U8],
323        key: KeyRef<'a, Self>,
324        nonce: NonceRef<'a, Self>,
325        aad: &[u8],
326        ciphertext: &[u8],
327        tag: TagRef<'a, Self>,
328    ) -> Result<(), DecryptError> {
329        if key.algo() != self {
330            return Err(DecryptError::WrongKey);
331        }
332        if tag.algo() != self {
333            return Err(DecryptError::WrongTag);
334        }
335        if nonce.algo() != self {
336            return Err(DecryptError::WrongNonce);
337        }
338
339        // now we expect the lengths to be correct, so later mismatches are unknown errors
340        let key: &[U8; KEY_LEN] = key.as_ref().try_into().map_err(|_| DecryptError::Unknown)?;
341
342        let tag: &[U8; TAG_LEN] = tag.as_ref().try_into().map_err(|_| DecryptError::Unknown)?;
343
344        let nonce: &[U8; NONCE_LEN] = nonce
345            .as_ref()
346            .try_into()
347            .map_err(|_| DecryptError::Unknown)?;
348
349        <Self as super::typed_owned::Aead>::decrypt(
350            plaintext,
351            key.into(),
352            nonce.into(),
353            aad,
354            ciphertext,
355            tag.into(),
356        )
357        .map_err(DecryptError::from)
358    }
359}
360
361#[derive(Debug, Clone, Copy)]
362pub struct WrongLengthError;
363
364impl<'a, Algo: Aead> KeyRef<'a, Algo> {
365    /// Creates a new key for the provided algorithm. Checks that the length is correct.
366    pub fn new_for_algo(algo: Algo, key: &'a [U8]) -> Result<Self, WrongLengthError> {
367        (key.len() == algo.key_len())
368            .then_some(KeyRef {
369                algorithm: algo,
370                key,
371            })
372            .ok_or(WrongLengthError)
373    }
374
375    /// Performs AEAD encryption. If algo is multiplexed, it checks that the algorithms specified
376    /// in the key, nonce and tag are consistent.
377    pub fn encrypt(
378        &self,
379        ciphertext: &mut [u8],
380        tag: TagMut<'a, Algo>,
381        nonce: NonceRef<'a, Algo>,
382        aad: &[u8],
383        plaintext: &[U8],
384    ) -> Result<(), EncryptError> {
385        self.algorithm
386            .encrypt(ciphertext, tag, *self, nonce, aad, plaintext)
387    }
388
389    /// Performs AEAD decryption. If algo is multiplexed, it checks that the algorithms specified
390    /// in the key, nonce and tag are consistent.
391    pub fn decrypt(
392        &self,
393        plaintext: &mut [U8],
394        nonce: NonceRef<'a, Algo>,
395        aad: &[u8],
396        ciphertext: &[u8],
397        tag: TagRef<'a, Algo>,
398    ) -> Result<(), DecryptError> {
399        self.algorithm
400            .decrypt(plaintext, *self, nonce, aad, ciphertext, tag)
401    }
402}
403
404impl<'a, Algo: Aead> AsRef<[U8]> for KeyRef<'a, Algo> {
405    fn as_ref(&self) -> &[U8] {
406        self.key
407    }
408}
409
410impl<'a, Algo: Aead> AsMut<[U8]> for KeyMut<'a, Algo> {
411    fn as_mut(&mut self) -> &mut [U8] {
412        self.key
413    }
414}
415
416impl<'a, Algo> KeyRef<'a, Algo> {
417    /// Returns the algorithm this key should be used in
418    pub fn algo(&self) -> &Algo {
419        &self.algorithm
420    }
421}
422
423impl<'a, Algo: Aead> KeyMut<'a, Algo> {
424    /// Creates a new mutable key for the provided algorithm. Checks that the length is correct.
425    pub fn new_for_algo(algo: Algo, key: &'a mut [U8]) -> Result<Self, WrongLengthError> {
426        (key.len() == algo.key_len())
427            .then_some(KeyMut {
428                algorithm: algo,
429                key,
430            })
431            .ok_or(WrongLengthError)
432    }
433}
434
435impl<'a, Algo> KeyMut<'a, Algo> {
436    /// Returns the algorithm this key should be used in
437    pub fn algo(&self) -> &Algo {
438        &self.algorithm
439    }
440}
441
442impl<'a, Algo: Aead> TagRef<'a, Algo> {
443    /// Creates a new tag for the provided algorithm. Checks that the length is correct.
444    pub fn new_for_algo(algo: Algo, tag: &'a [U8]) -> Result<Self, WrongLengthError> {
445        (tag.len() == algo.tag_len())
446            .then_some(TagRef {
447                algorithm: algo,
448                tag,
449            })
450            .ok_or(WrongLengthError)
451    }
452}
453
454impl<'a, Algo: Aead> AsRef<[U8]> for TagRef<'a, Algo> {
455    fn as_ref(&self) -> &[U8] {
456        self.tag
457    }
458}
459
460impl<'a, Algo> TagRef<'a, Algo> {
461    /// Returns the algorithm this tag should be used in
462    pub fn algo(&self) -> &Algo {
463        &self.algorithm
464    }
465}
466
467impl<'a, Algo: Aead> TagMut<'a, Algo> {
468    /// Creates a new mutable tag for the provided algorithm. Checks that the length is correct.
469    pub fn new_for_algo(algo: Algo, tag: &'a mut [U8]) -> Result<Self, WrongLengthError> {
470        (tag.len() == algo.tag_len())
471            .then_some(TagMut {
472                algorithm: algo,
473                tag,
474            })
475            .ok_or(WrongLengthError)
476    }
477}
478
479impl<'a, Algo: Aead> From<TagMut<'a, Algo>> for TagRef<'a, Algo> {
480    fn from(tag: TagMut<'a, Algo>) -> Self {
481        TagRef {
482            algorithm: tag.algorithm,
483            tag: tag.tag,
484        }
485    }
486}
487
488impl<'a, Algo> TagMut<'a, Algo> {
489    /// Returns the algorithm this mutable tag should be used in
490    pub fn algo(&self) -> &Algo {
491        &self.algorithm
492    }
493}
494
495impl<'a, Algo: Aead> NonceRef<'a, Algo> {
496    /// Creates a new nonce for the provided algorithm. Checks that the length is correct.
497    pub fn new_for_algo(algo: Algo, nonce: &'a [U8]) -> Result<Self, WrongLengthError> {
498        (nonce.len() == algo.nonce_len())
499            .then_some(NonceRef {
500                algorithm: algo,
501                nonce,
502            })
503            .ok_or(WrongLengthError)
504    }
505}
506
507impl<'a, Algo> NonceRef<'a, Algo> {
508    /// Returns the algorithm this nonce should be used in
509    pub fn algo(&self) -> &Algo {
510        &self.algorithm
511    }
512}
513
514impl<'a, Algo: Aead> AsRef<[U8]> for NonceRef<'a, Algo> {
515    fn as_ref(&self) -> &[U8] {
516        self.nonce
517    }
518}
519
520impl<'a, Algo: Aead> AsMut<[U8]> for TagMut<'a, Algo> {
521    fn as_mut(&mut self) -> &mut [U8] {
522        self.tag
523    }
524}
525
526/// This trait is implemented by the multiplexing enum, once per actual algorithm.
527/// It allows users (and internal code) to convert between structs with the actual algorithm and
528/// the multiplexing enum.
529pub trait Multiplexes<Algo>: Aead + Sized {
530    /// If self is actually algorithm `Algo`, return that.
531    fn mux_algo(&self) -> Option<Algo>;
532
533    /// Create a new multiplexed algorithm value that has `algo` as actual algorithm.
534    fn wrap_algo(algo: Algo) -> Self;
535
536    /// Tries unwrapping the algorithm in a key
537    fn mux_key<'a>(key: KeyRef<'a, Self>) -> Option<KeyRef<'a, Algo>> {
538        let KeyRef { algorithm, key } = key;
539        algorithm
540            .mux_algo()
541            .map(|algorithm| KeyRef { algorithm, key })
542    }
543
544    /// Wraps the algorithm in a key
545    fn wrap_key<'a>(k: KeyRef<'a, Algo>) -> KeyRef<'a, Self> {
546        KeyRef {
547            algorithm: Self::wrap_algo(k.algorithm),
548            key: k.key,
549        }
550    }
551
552    /// Tries unwrapping the algorithm in a mutable key
553    fn mux_key_mut<'a>(key: KeyMut<'a, Self>) -> Option<KeyMut<'a, Algo>> {
554        let KeyMut { algorithm, key } = key;
555        algorithm
556            .mux_algo()
557            .map(|algorithm| KeyMut { algorithm, key })
558    }
559
560    /// Wraps the algorithm in a mutable key
561    fn wrap_key_mut<'a>(k: KeyMut<'a, Algo>) -> KeyMut<'a, Self> {
562        KeyMut {
563            algorithm: Self::wrap_algo(k.algorithm),
564            key: k.key,
565        }
566    }
567
568    /// Tries unwrapping the algorithm in a tag
569    fn mux_tag<'a>(tag: TagRef<'a, Self>) -> Option<TagRef<'a, Algo>> {
570        let TagRef { algorithm, tag } = tag;
571        algorithm
572            .mux_algo()
573            .map(|algorithm| TagRef { algorithm, tag })
574    }
575
576    /// Wraps the algorithm in a tag
577    fn wrap_tag<'a>(tag: TagRef<'a, Algo>) -> TagRef<'a, Self> {
578        TagRef {
579            algorithm: Self::wrap_algo(tag.algorithm),
580            tag: tag.tag,
581        }
582    }
583
584    /// Tries unwrapping the algorithm in a mutable tag
585    fn mux_tag_mut<'a>(tag: TagMut<'a, Self>) -> Option<TagMut<'a, Algo>> {
586        let TagMut { algorithm, tag } = tag;
587        algorithm
588            .mux_algo()
589            .map(|algorithm| TagMut { algorithm, tag })
590    }
591
592    /// Wraps the algorithm in a mutable tag
593    fn wrap_tag_mut<'a>(tag: TagMut<'a, Algo>) -> TagMut<'a, Self> {
594        TagMut {
595            algorithm: Self::wrap_algo(tag.algorithm),
596            tag: tag.tag,
597        }
598    }
599
600    /// Tries unwrapping the algorithm in a nonce
601    fn mux_nonce<'a>(nonce: NonceRef<'a, Self>) -> Option<NonceRef<'a, Algo>> {
602        let NonceRef { algorithm, nonce } = nonce;
603        algorithm
604            .mux_algo()
605            .map(|algorithm| NonceRef { algorithm, nonce })
606    }
607
608    /// Wraps the algorithm in a nonce
609    fn wrap_nonce<'a>(nonce: NonceRef<'a, Algo>) -> NonceRef<'a, Self> {
610        NonceRef {
611            algorithm: Self::wrap_algo(nonce.algorithm),
612            nonce: nonce.nonce,
613        }
614    }
615}