ascon_aead/
lib.rs

1// Copyright 2021-2025 Sebastian Ramacher
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3
4#![no_std]
5#![cfg_attr(docsrs, feature(doc_auto_cfg))]
6#![doc = include_str!("../README.md")]
7#![warn(missing_docs)]
8
9//! ## Usage
10//!
11//! Simple usage (allocating, no associated data):
12//!
13//! ```
14//! use ascon_aead::{AsconAead128, AsconAead128Key, AsconAead128Nonce, Key, Nonce};
15//! use ascon_aead::aead::{Aead, KeyInit};
16//!
17//! let key = AsconAead128Key::from_slice(b"very secret key.");
18//! let cipher = AsconAead128::new(key);
19//!
20//! // 128-bits; unique per message
21//! let nonce = AsconAead128Nonce::from_slice(b"unique nonce 012");
22//!
23//! let ciphertext = cipher.encrypt(nonce, b"plaintext message".as_ref())
24//!     .expect("encryption failure!"); // NOTE: handle this error to avoid panics!
25//!
26//! let plaintext = cipher.decrypt(nonce, ciphertext.as_ref())
27//!     .expect("decryption failure!"); // NOTE: handle this error to avoid panics!
28//!
29//! assert_eq!(&plaintext, b"plaintext message");
30//! ```
31//!
32//! With randomly sampled keys and nonces (requires `getrandom` feature):
33//!
34//! ```
35//! # #[cfg(feature = "getrandom")] {
36//! use ascon_aead::AsconAead128;
37//! use ascon_aead::aead::{Aead, AeadCore, KeyInit, OsRng};
38//!
39//! let key = AsconAead128::generate_key(&mut OsRng);
40//! let cipher = AsconAead128::new(&key);
41//!
42//! // 128 bits; unique per message
43//! let nonce = AsconAead128::generate_nonce(&mut OsRng);
44//!
45//! let ciphertext = cipher.encrypt(&nonce, b"plaintext message".as_ref())
46//!     .expect("encryption failure!"); // NOTE: handle this error to avoid panics!
47//!
48//! let plaintext = cipher.decrypt(&nonce, ciphertext.as_ref())
49//!     .expect("decryption failure!"); // NOTE: handle this error to avoid panics!
50//!
51//! assert_eq!(&plaintext, b"plaintext message");
52//! # }
53//! ```
54//!
55//! ## In-place Usage (eliminates `alloc` requirement)
56//!
57//! This crate has an optional `alloc` feature which can be disabled in e.g.
58//! microcontroller environments that don't have a heap.
59//!
60//! The [`AeadInPlace::encrypt_in_place`] and [`AeadInPlace::decrypt_in_place`]
61//! methods accept any type that impls the [`aead::Buffer`] trait which
62//! contains the plaintext for encryption or ciphertext for decryption.
63//!
64//! Note that if you enable the `heapless` feature of this crate,
65//! you will receive an impl of [`aead::Buffer`] for `heapless::Vec`
66//! (re-exported from the [`aead`] crate as [`aead::heapless::Vec`]),
67//! which can then be passed as the `buffer` parameter to the in-place encrypt
68//! and decrypt methods:
69//!
70//! ```
71//! # #[cfg(feature = "heapless")] {
72//! use ascon_aead::{AsconAead128, AsconAead128Key, AsconAead128Nonce, Key, Nonce};
73//! use ascon_aead::aead::{AeadInPlace, KeyInit};
74//! use ascon_aead::aead::heapless::Vec;
75//!
76//! let key = AsconAead128Key::from_slice(b"very secret key.");
77//! let cipher = AsconAead128::new(key);
78//!
79//! // 128-bits; unique per message
80//! let nonce = AsconAead128Nonce::from_slice(b"unique nonce 012");
81//!
82//! // Buffer needs 16-bytes overhead for authentication tag
83//! let mut buffer: Vec<u8, 128> = Vec::new();
84//! buffer.extend_from_slice(b"plaintext message");
85//!
86//! // Encrypt `buffer` in-place, replacing the plaintext contents with ciphertext
87//! cipher.encrypt_in_place(nonce, b"", &mut buffer).expect("encryption failure!");
88//!
89//! // `buffer` now contains the message ciphertext
90//! assert_ne!(&buffer, b"plaintext message");
91//!
92//! // Decrypt `buffer` in-place, replacing its ciphertext context with the original plaintext
93//! cipher.decrypt_in_place(nonce, b"", &mut buffer).expect("decryption failure!");
94//! assert_eq!(&buffer, b"plaintext message");
95//! # }
96//! ```
97//!
98//! Similarly, enabling the `arrayvec` feature of this crate will provide an impl of
99//! [`aead::Buffer`] for `arrayvec::ArrayVec` (re-exported from the [`aead`] crate as
100//! [`aead::arrayvec::ArrayVec`]), and enabling the `bytes` feature of this crate will
101//! provide an impl of [`aead::Buffer`] for `bytes::BytesMut` (re-exported from the
102//! [`aead`] crate as [`aead::bytes::BytesMut`]).
103//!
104//! ## Truncated Tags
105//!
106//! Ascon-AEAD128 also supports truncated tags ranging from 32 to 128 bits.
107//! Currently, only byte lengths are supported. Support for truncated tags is
108//! available via [`TruncatedAsconAEAD128`].
109//!
110//! ```
111//! use aead::consts::{U5};
112//! use ascon_aead::{TruncatedAsconAead128, Key, Nonce};
113//! use ascon_aead::aead::{Aead, KeyInit};
114//!
115//! type TruncatedAscon = TruncatedAsconAead128<U5>;
116//! let key = Key::<TruncatedAscon>::from_slice(b"very secret key.");
117//! let cipher = TruncatedAscon::new(key);
118//!
119//! // 128-bits; unique per message
120//! let nonce = Nonce::<TruncatedAscon>::from_slice(b"unique nonce 012");
121//!
122//! let ciphertext = cipher.encrypt(nonce, b"plaintext message".as_ref())
123//!     .expect("encryption failure!"); // NOTE: handle this error to avoid panics!
124//!
125//! let plaintext = cipher.decrypt(nonce, ciphertext.as_ref())
126//!     .expect("decryption failure!"); // NOTE: handle this error to avoid panics!
127//!
128//! assert_eq!(&plaintext, b"plaintext message");
129//! ```
130
131pub use aead::{self, Error, Key, Nonce, Tag};
132use aead::{
133    AeadCore, AeadInPlace, KeyInit, KeySizeUser,
134    consts::{True, U0, U4, U16},
135    generic_array::{
136        ArrayLength,
137        typenum::{IsGreaterOrEqual, IsLessOrEqual},
138    },
139};
140
141mod asconcore;
142
143use asconcore::{AsconCore, Parameters, Parameters128};
144
145/// Ascon generic over some Parameters
146///
147/// This type is generic to support substituting various Ascon parameter sets. It is not intended to
148/// be uses directly. Use the [`AsconAead128`] type aliases instead.
149#[derive(Clone)]
150struct Ascon<P: Parameters> {
151    key: P::InternalKey,
152}
153
154impl<P: Parameters> KeySizeUser for Ascon<P> {
155    type KeySize = P::KeySize;
156}
157
158impl<P: Parameters> KeyInit for Ascon<P> {
159    fn new(key: &Key<Self>) -> Self {
160        Self {
161            key: P::InternalKey::from(key),
162        }
163    }
164}
165
166impl<P: Parameters> AeadCore for Ascon<P> {
167    type NonceSize = U16;
168    type TagSize = P::TagSize;
169    type CiphertextOverhead = U0;
170}
171
172impl<P: Parameters> AeadInPlace for Ascon<P> {
173    fn encrypt_in_place_detached(
174        &self,
175        nonce: &Nonce<Self>,
176        associated_data: &[u8],
177        buffer: &mut [u8],
178    ) -> Result<Tag<Self>, Error> {
179        if (buffer.len() as u64)
180            .checked_add(associated_data.len() as u64)
181            .is_none()
182        {
183            return Err(Error);
184        }
185
186        let mut core = AsconCore::<P>::new(&self.key, nonce);
187        Ok(core.encrypt_inplace(buffer, associated_data))
188    }
189
190    fn decrypt_in_place_detached(
191        &self,
192        nonce: &Nonce<Self>,
193        associated_data: &[u8],
194        buffer: &mut [u8],
195        tag: &Tag<Self>,
196    ) -> Result<(), Error> {
197        if (buffer.len() as u64)
198            .checked_add(associated_data.len() as u64)
199            .is_none()
200        {
201            return Err(Error);
202        }
203
204        let mut core = AsconCore::<P>::new(&self.key, nonce);
205        core.decrypt_inplace(buffer, associated_data, tag)
206    }
207}
208
209/// Ascon-AEAD128
210pub struct AsconAead128(Ascon<Parameters128<U16>>);
211/// Key for Ascon-AEAD128
212pub type AsconAead128Key = Key<AsconAead128>;
213/// Nonce for Ascon-AEAD128
214pub type AsconAead128Nonce = Nonce<AsconAead128>;
215/// Tag for Ascon-AEAD128
216pub type AsconAead128Tag = Tag<AsconAead128>;
217
218impl KeySizeUser for AsconAead128 {
219    type KeySize = U16;
220}
221
222impl KeyInit for AsconAead128 {
223    fn new(key: &Key<Self>) -> Self {
224        Self(Ascon::new(key))
225    }
226}
227
228impl AeadCore for AsconAead128 {
229    type NonceSize = U16;
230    type TagSize = U16;
231    type CiphertextOverhead = U0;
232}
233
234impl AeadInPlace for AsconAead128 {
235    #[inline(always)]
236    fn encrypt_in_place_detached(
237        &self,
238        nonce: &Nonce<Self>,
239        associated_data: &[u8],
240        buffer: &mut [u8],
241    ) -> Result<Tag<Self>, Error> {
242        self.0
243            .encrypt_in_place_detached(nonce, associated_data, buffer)
244    }
245
246    #[inline(always)]
247    fn decrypt_in_place_detached(
248        &self,
249        nonce: &Nonce<Self>,
250        associated_data: &[u8],
251        buffer: &mut [u8],
252        tag: &Tag<Self>,
253    ) -> Result<(), Error> {
254        self.0
255            .decrypt_in_place_detached(nonce, associated_data, buffer, tag)
256    }
257}
258
259/// Truncated Ascon-AEAD128
260///
261/// Tag sizes of 4 to 16 bytes are supported.
262pub struct TruncatedAsconAead128<TagSize = U16>(Ascon<Parameters128<TagSize>>)
263where
264    TagSize:
265        ArrayLength<u8> + IsLessOrEqual<U16, Output = True> + IsGreaterOrEqual<U4, Output = True>;
266/// Key for Truncated Ascon-AEAD128
267pub type TruncatedAsconAead128Key<TagSize = U16> = Key<TruncatedAsconAead128<TagSize>>;
268/// Nonce for Truncated Ascon-AEAD128
269pub type TruncatedAsconAead128Nonce<TagSize = U16> = Nonce<TruncatedAsconAead128<TagSize>>;
270/// Tag for Truncated  Ascon-AEAD128
271pub type TruncatedAsconAead128Tag<TagSize = U16> = Tag<TruncatedAsconAead128<TagSize>>;
272
273impl<TagSize> KeySizeUser for TruncatedAsconAead128<TagSize>
274where
275    TagSize:
276        ArrayLength<u8> + IsLessOrEqual<U16, Output = True> + IsGreaterOrEqual<U4, Output = True>,
277{
278    type KeySize = U16;
279}
280
281impl<TagSize> KeyInit for TruncatedAsconAead128<TagSize>
282where
283    TagSize:
284        ArrayLength<u8> + IsLessOrEqual<U16, Output = True> + IsGreaterOrEqual<U4, Output = True>,
285{
286    fn new(key: &Key<Self>) -> Self {
287        Self(Ascon::new(key))
288    }
289}
290
291impl<TagSize> AeadCore for TruncatedAsconAead128<TagSize>
292where
293    TagSize:
294        ArrayLength<u8> + IsLessOrEqual<U16, Output = True> + IsGreaterOrEqual<U4, Output = True>,
295{
296    type NonceSize = U16;
297    type TagSize = TagSize;
298    type CiphertextOverhead = U0;
299}
300
301impl<TagSize> AeadInPlace for TruncatedAsconAead128<TagSize>
302where
303    TagSize:
304        ArrayLength<u8> + IsLessOrEqual<U16, Output = True> + IsGreaterOrEqual<U4, Output = True>,
305{
306    #[inline(always)]
307    fn encrypt_in_place_detached(
308        &self,
309        nonce: &Nonce<Self>,
310        associated_data: &[u8],
311        buffer: &mut [u8],
312    ) -> Result<Tag<Self>, Error> {
313        self.0
314            .encrypt_in_place_detached(nonce, associated_data, buffer)
315    }
316
317    #[inline(always)]
318    fn decrypt_in_place_detached(
319        &self,
320        nonce: &Nonce<Self>,
321        associated_data: &[u8],
322        buffer: &mut [u8],
323        tag: &Tag<Self>,
324    ) -> Result<(), Error> {
325        self.0
326            .decrypt_in_place_detached(nonce, associated_data, buffer, tag)
327    }
328}