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}