Skip to content

Commit 27d714b

Browse files
committed
[WIP] aead: add PrefixNonceAead
1 parent e4d7d34 commit 27d714b

2 files changed

Lines changed: 184 additions & 0 deletions

File tree

aead/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,18 @@
88
#![forbid(unsafe_code)]
99

1010
#[cfg(feature = "alloc")]
11+
#[macro_use]
1112
extern crate alloc;
1213

1314
#[cfg(feature = "dev")]
1415
pub mod dev;
16+
mod prefix_nonce;
1517

1618
pub use common::{
1719
self, Key, KeyInit, KeySizeUser,
1820
array::{self, typenum::consts},
1921
};
22+
pub use prefix_nonce::PrefixNonceAead;
2023

2124
#[cfg(feature = "arrayvec")]
2225
pub use arrayvec;

aead/src/prefix_nonce.rs

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
use crate::{AeadCore, AeadInOut, Buffer, Error, Nonce, Payload, Result, Tag};
2+
use common::{Key, KeyInit, KeySizeUser, typenum::Unsigned};
3+
use inout::InOutBuf;
4+
5+
#[cfg(feature = "alloc")]
6+
use alloc::vec::Vec;
7+
#[cfg(feature = "getrandom")]
8+
use common::getrandom::SysRng;
9+
#[cfg(feature = "rand_core")]
10+
use common::{Generate, rand_core::TryCryptoRng};
11+
12+
/// AEAD which uses nonce-prefixed ciphertext messages.
13+
#[derive(Clone, Debug)]
14+
#[repr(transparent)]
15+
pub struct PrefixNonceAead<A> {
16+
/// Inner AEAD.
17+
aead: A,
18+
}
19+
20+
impl<A: KeySizeUser> KeySizeUser for PrefixNonceAead<A> {
21+
type KeySize = A::KeySize;
22+
}
23+
24+
impl<A: KeyInit> KeyInit for PrefixNonceAead<A> {
25+
fn new(key: &Key<Self>) -> Self {
26+
Self { aead: A::new(key) }
27+
}
28+
}
29+
30+
impl<A: AeadInOut> PrefixNonceAead<A> {
31+
/// Encrypt the given `plaintext` under a randomly generated nonce, returning a byte vector.
32+
///
33+
/// # Errors
34+
/// TODO
35+
#[cfg(all(feature = "alloc", feature = "getrandom"))]
36+
pub fn encrypt_to_vec<'msg, 'aad>(
37+
&self,
38+
plaintext: impl Into<Payload<'msg, 'aad>>,
39+
) -> Result<Vec<u8>> {
40+
let plaintext = plaintext.into();
41+
let mut out = Vec::with_capacity(
42+
A::NonceSize::USIZE
43+
.saturating_add(plaintext.msg.len())
44+
.saturating_add(A::TagSize::USIZE),
45+
);
46+
self.encrypt_to_buffer(plaintext, &mut out)?;
47+
Ok(out)
48+
}
49+
50+
/// Encrypt the given `plaintext` under a randomly generated nonce, writing output to the given
51+
/// `ciphertext` buffer.
52+
///
53+
/// # Errors
54+
/// TODO
55+
#[cfg(feature = "getrandom")]
56+
pub fn encrypt_to_buffer<'msg, 'aad>(
57+
&self,
58+
plaintext: impl Into<Payload<'msg, 'aad>>,
59+
ciphertext: &mut impl Buffer,
60+
) -> Result<()> {
61+
self.encrypt_with_rng_to_buffer(&mut SysRng, plaintext, ciphertext)
62+
}
63+
64+
/// Generate a random nonce from the provided RNG and encrypt the given `plaintext`, writing
65+
/// output to the given `ciphertext` buffer.
66+
///
67+
/// # Errors
68+
/// TODO
69+
#[cfg(feature = "rand_core")]
70+
pub fn encrypt_with_rng_to_buffer<'msg, 'aad, R: TryCryptoRng + ?Sized>(
71+
&self,
72+
rng: &mut R,
73+
plaintext: impl Into<Payload<'msg, 'aad>>,
74+
ciphertext: &mut impl Buffer,
75+
) -> Result<()> {
76+
let nonce = Nonce::<A>::try_generate_from_rng(rng).map_err(|_| Error)?;
77+
self.encrypt_with_nonce_to_buffer(&nonce, plaintext, ciphertext)
78+
}
79+
80+
/// Encrypt the given `plaintext` under the provided `nonce`, prepending it to the `ciphertext`.
81+
///
82+
/// # Errors
83+
/// TODO
84+
pub fn encrypt_with_nonce_to_buffer<'msg, 'aad>(
85+
&self,
86+
nonce: &Nonce<A>,
87+
plaintext: impl Into<Payload<'msg, 'aad>>,
88+
ciphertext: &mut impl Buffer,
89+
) -> Result<()> {
90+
let plaintext = plaintext.into();
91+
ciphertext.extend_from_slice(nonce)?;
92+
ciphertext.extend_from_slice(plaintext.msg)?;
93+
94+
let tag = self.aead.encrypt_inout_detached(
95+
nonce,
96+
plaintext.aad,
97+
(&mut ciphertext.as_mut()[A::NonceSize::USIZE..]).into(),
98+
)?;
99+
100+
ciphertext.extend_from_slice(&tag)?;
101+
Ok(())
102+
}
103+
104+
/// Decrypt a [`Buffer`] containing a ciphertext message in-place, leaving the plaintext message
105+
/// as its contents upon success.
106+
///
107+
/// # Errors
108+
/// TODO
109+
pub fn decrypt_in_place(&self, aad: &[u8], buffer: &mut impl Buffer) -> Result<()> {
110+
let (nonce, buf, tag) = decode_mut_aead_msg::<A>(buffer.as_mut())?;
111+
let ct_len = buf.len();
112+
self.aead
113+
.decrypt_inout_detached(&nonce, aad, buf.into(), &tag)?;
114+
115+
// Place the decrypted plaintext message at the beginning of the buffer by copying it over
116+
// the prefix nonce
117+
let ct_end = A::NonceSize::USIZE.saturating_add(ct_len);
118+
buffer.as_mut().copy_within(A::NonceSize::USIZE..ct_end, 0);
119+
buffer.truncate(ct_len);
120+
Ok(())
121+
}
122+
123+
/// Decrypt the provided `ciphertext` message which includes a prepended nonce to the given
124+
/// byte slice output buffer.
125+
///
126+
/// # Errors
127+
/// TODO
128+
pub fn decrypt_to_slice<'msg, 'aad>(
129+
&self,
130+
ciphertext: impl Into<Payload<'msg, 'aad>>,
131+
out: &mut [u8],
132+
) -> Result<()> {
133+
let payload = ciphertext.into();
134+
let (nonce, ct, tag) = decode_aead_msg::<A>(payload.msg)?;
135+
let buf = InOutBuf::new(ct, out).map_err(|_| Error)?;
136+
self.aead
137+
.decrypt_inout_detached(&nonce, payload.aad, buf, &tag)
138+
}
139+
140+
/// Decrypt the provided `ciphertext` message which includes a prepended nonce, returning a byte
141+
/// vector upon success.
142+
///
143+
/// # Errors
144+
/// TODO
145+
#[cfg(feature = "alloc")]
146+
pub fn decrypt_to_vec<'msg, 'aad>(
147+
&self,
148+
ciphertext: impl Into<Payload<'msg, 'aad>>,
149+
) -> Result<Vec<u8>> {
150+
let ciphertext = ciphertext.into();
151+
let plaintext_len = ciphertext
152+
.msg
153+
.len()
154+
.saturating_sub(A::NonceSize::USIZE)
155+
.saturating_sub(A::TagSize::USIZE);
156+
let mut out = vec![0u8; plaintext_len];
157+
self.decrypt_to_slice(ciphertext, &mut out)?;
158+
Ok(out)
159+
}
160+
}
161+
162+
/// Decode an AEAD message from the given byte slice.
163+
fn decode_aead_msg<A: AeadCore>(ciphertext: &[u8]) -> Result<(Nonce<A>, &[u8], Tag<A>)> {
164+
let (nonce, rest) = ciphertext
165+
.split_at_checked(A::NonceSize::USIZE)
166+
.ok_or(Error)?;
167+
let (ciphertext, tag) = rest.split_at_checked(A::TagSize::USIZE).ok_or(Error)?;
168+
let nonce = Nonce::<A>::try_from(nonce).map_err(|_| Error)?;
169+
let tag = Tag::<A>::try_from(tag).map_err(|_| Error)?;
170+
Ok((nonce, ciphertext, tag))
171+
}
172+
173+
/// Decode an AEAD message from a mutable input buffer, returning the mutable ciphertext message
174+
/// portion for use with in-place encryption.
175+
fn decode_mut_aead_msg<A: AeadCore>(
176+
ciphertext: &mut [u8],
177+
) -> Result<(Nonce<A>, &mut [u8], Tag<A>)> {
178+
let (nonce, ct, tag) = decode_aead_msg::<A>(ciphertext)?;
179+
let ct_len = ct.len();
180+
Ok((nonce, &mut ciphertext[A::NonceSize::USIZE..][ct_len..], tag))
181+
}

0 commit comments

Comments
 (0)