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, Key, Nonce};
15//! use ascon_aead::aead::{Aead, KeyInit};
16//!
17//! let key = Key::<AsconAead128>::from_slice(b"very secret key.");
18//! let cipher = AsconAead128::new(key);
19//!
20//! let nonce = Nonce::<AsconAead128>::from_slice(b"unique nonce 012"); // 128-bits; unique per message
21//!
22//! let ciphertext = cipher.encrypt(nonce, b"plaintext message".as_ref())
23//!     .expect("encryption failure!"); // NOTE: handle this error to avoid panics!
24//!
25//! let plaintext = cipher.decrypt(nonce, ciphertext.as_ref())
26//!     .expect("decryption failure!"); // NOTE: handle this error to avoid panics!
27//!
28//! assert_eq!(&plaintext, b"plaintext message");
29//! ```
30//!
31//! With randomly sampled keys and nonces (requires `getrandom` feature):
32//!
33//! ```
34//! # #[cfg(feature = "getrandom")] {
35//! use ascon_aead::AsconAead128;
36//! use ascon_aead::aead::{Aead, AeadCore, KeyInit, OsRng};
37//!
38//! let key = AsconAead128::generate_key(&mut OsRng);
39//! let cipher = AsconAead128::new(&key);
40//!
41//! let nonce = AsconAead128::generate_nonce(&mut OsRng); // 128 bits; unique per message
42//!
43//! let ciphertext = cipher.encrypt(&nonce, b"plaintext message".as_ref())
44//!     .expect("encryption failure!"); // NOTE: handle this error to avoid panics!
45//!
46//! let plaintext = cipher.decrypt(&nonce, ciphertext.as_ref())
47//!     .expect("decryption failure!"); // NOTE: handle this error to avoid panics!
48//!
49//! assert_eq!(&plaintext, b"plaintext message");
50//! # }
51//! ```
52//!
53//! ## In-place Usage (eliminates `alloc` requirement)
54//!
55//! This crate has an optional `alloc` feature which can be disabled in e.g.
56//! microcontroller environments that don't have a heap.
57//!
58//! The [`AeadInPlace::encrypt_in_place`] and [`AeadInPlace::decrypt_in_place`]
59//! methods accept any type that impls the [`aead::Buffer`] trait which
60//! contains the plaintext for encryption or ciphertext for decryption.
61//!
62//! Note that if you enable the `heapless` feature of this crate,
63//! you will receive an impl of [`aead::Buffer`] for `heapless::Vec`
64//! (re-exported from the [`aead`] crate as [`aead::heapless::Vec`]),
65//! which can then be passed as the `buffer` parameter to the in-place encrypt
66//! and decrypt methods:
67//!
68//! ```
69//! # #[cfg(feature = "heapless")] {
70//! use ascon_aead::{AsconAead128, Key, Nonce};
71//! use ascon_aead::aead::{AeadInPlace, KeyInit};
72//! use ascon_aead::aead::heapless::Vec;
73//!
74//! let key = Key::<AsconAead128>::from_slice(b"very secret key.");
75//! let cipher = AsconAead128::new(key);
76//!
77//! let nonce = Nonce::<AsconAead128>::from_slice(b"unique nonce 012"); // 128-bits; unique per message
78//!
79//! let mut buffer: Vec<u8, 128> = Vec::new(); // Buffer needs 16-bytes overhead for authentication tag
80//! buffer.extend_from_slice(b"plaintext message");
81//!
82//! // Encrypt `buffer` in-place, replacing the plaintext contents with ciphertext
83//! cipher.encrypt_in_place(nonce, b"", &mut buffer).expect("encryption failure!");
84//!
85//! // `buffer` now contains the message ciphertext
86//! assert_ne!(&buffer, b"plaintext message");
87//!
88//! // Decrypt `buffer` in-place, replacing its ciphertext context with the original plaintext
89//! cipher.decrypt_in_place(nonce, b"", &mut buffer).expect("decryption failure!");
90//! assert_eq!(&buffer, b"plaintext message");
91//! # }
92//! ```
93//!
94//! Similarly, enabling the `arrayvec` feature of this crate will provide an impl of
95//! [`aead::Buffer`] for `arrayvec::ArrayVec` (re-exported from the [`aead`] crate as
96//! [`aead::arrayvec::ArrayVec`]), and enabling the `bytes` feature of this crate will
97//! provide an impl of [`aead::Buffer`] for `bytes::BytesMut` (re-exported from the
98//! [`aead`] crate as [`aead::bytes::BytesMut`]).
99
100pub use aead::{self, Error, Key, Nonce, Tag};
101use aead::{
102    AeadCore, AeadInPlace, KeyInit, KeySizeUser,
103    consts::{U0, U16},
104};
105
106mod asconcore;
107
108use asconcore::{AsconCore, Parameters, Parameters128};
109
110/// Ascon generic over some Parameters
111///
112/// This type is generic to support substituting various Ascon parameter sets. It is not intended to
113/// be uses directly. Use the [`AsconAead128`] type aliases instead.
114#[derive(Clone)]
115struct Ascon<P: Parameters> {
116    key: P::InternalKey,
117}
118
119impl<P: Parameters> KeySizeUser for Ascon<P> {
120    type KeySize = P::KeySize;
121}
122
123impl<P: Parameters> KeyInit for Ascon<P> {
124    fn new(key: &Key<Self>) -> Self {
125        Self {
126            key: P::InternalKey::from(key),
127        }
128    }
129}
130
131impl<P: Parameters> AeadCore for Ascon<P> {
132    type NonceSize = U16;
133    type TagSize = U16;
134    type CiphertextOverhead = U0;
135}
136
137impl<P: Parameters> AeadInPlace for Ascon<P> {
138    fn encrypt_in_place_detached(
139        &self,
140        nonce: &Nonce<Self>,
141        associated_data: &[u8],
142        buffer: &mut [u8],
143    ) -> Result<Tag<Self>, Error> {
144        if (buffer.len() as u64)
145            .checked_add(associated_data.len() as u64)
146            .is_none()
147        {
148            return Err(Error);
149        }
150
151        let mut core = AsconCore::<P>::new(&self.key, nonce);
152        Ok(core.encrypt_inplace(buffer, associated_data))
153    }
154
155    fn decrypt_in_place_detached(
156        &self,
157        nonce: &Nonce<Self>,
158        associated_data: &[u8],
159        buffer: &mut [u8],
160        tag: &Tag<Self>,
161    ) -> Result<(), Error> {
162        if (buffer.len() as u64)
163            .checked_add(associated_data.len() as u64)
164            .is_none()
165        {
166            return Err(Error);
167        }
168
169        let mut core = AsconCore::<P>::new(&self.key, nonce);
170        core.decrypt_inplace(buffer, associated_data, tag)
171    }
172}
173
174/// Ascon-AEAD128
175pub struct AsconAead128(Ascon<Parameters128>);
176/// Key for Ascon-AEAD128
177pub type AsconAead128Key = Key<AsconAead128>;
178/// Nonce for Ascon-AEAD128
179pub type AsconAead128Nonce = Nonce<AsconAead128>;
180/// Tag for Ascon-AEAD128
181pub type AsconAead128Tag = Tag<AsconAead128>;
182
183impl KeySizeUser for AsconAead128 {
184    type KeySize = U16;
185}
186
187impl KeyInit for AsconAead128 {
188    fn new(key: &Key<Self>) -> Self {
189        Self(Ascon::<Parameters128>::new(key))
190    }
191}
192
193impl AeadCore for AsconAead128 {
194    type NonceSize = U16;
195    type TagSize = U16;
196    type CiphertextOverhead = U0;
197}
198
199impl AeadInPlace for AsconAead128 {
200    #[inline(always)]
201    fn encrypt_in_place_detached(
202        &self,
203        nonce: &Nonce<Self>,
204        associated_data: &[u8],
205        buffer: &mut [u8],
206    ) -> Result<Tag<Self>, Error> {
207        self.0
208            .encrypt_in_place_detached(nonce, associated_data, buffer)
209    }
210
211    #[inline(always)]
212    fn decrypt_in_place_detached(
213        &self,
214        nonce: &Nonce<Self>,
215        associated_data: &[u8],
216        buffer: &mut [u8],
217        tag: &Tag<Self>,
218    ) -> Result<(), Error> {
219        self.0
220            .decrypt_in_place_detached(nonce, associated_data, buffer, tag)
221    }
222}