Skip to content

Commit 0a483d1

Browse files
committed
aead: rework traits
1 parent 8bb3381 commit 0a483d1

File tree

6 files changed

+624
-363
lines changed

6 files changed

+624
-363
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

aead/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ rust-version = "1.81"
1717

1818
[dependencies]
1919
crypto-common = "0.2.0-rc.0"
20+
inout = "0.2.0-rc.1"
2021

2122
# optional dependencies
2223
arrayvec = { version = "0.7", optional = true, default-features = false }

aead/README.md

+36-2
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,43 @@ able to execute [chosen-ciphertext attacks]. The resulting security property,
1313
[ciphertext indistinguishability], is considered a basic requirement for
1414
modern cryptographic implementations.
1515

16-
See [RustCrypto/AEADs] for cipher implementations which use this trait.
16+
See [RustCrypto/AEADs] for cipher implementations which implement traits from
17+
this crate.
1718

18-
[Documentation][docs-link]
19+
## Nonces: ⚠️ Security Warning ⚠️
20+
21+
AEAD algorithms accept a parameter to encryption/decryption called
22+
a "nonce" which must be unique every time encryption is performed and
23+
never repeated for the same key. The nonce is often prepended to the
24+
ciphertext. The nonce used to produce a given ciphertext must be passed
25+
to the decryption function in order for it to decrypt correctly.
26+
27+
AEAD algorithms often fail catastrophically if nonces are ever repeated
28+
for the same key (with SIV modes being a "misuse-resistent" exception).
29+
30+
Nonces don't necessarily have to be random, but it is one strategy
31+
which is often used in practice.
32+
33+
Using random nonces runs the risk of repeating them unless the nonce
34+
size is particularly large, e.g. 192-bit extended nonces used by the
35+
`XChaCha20Poly1305` and `XSalsa20Poly1305` constructions.
36+
37+
[NIST SP 800-38D] recommends the following for 128-bit nonces:
38+
39+
> The total number of invocations of the authenticated encryption
40+
> function shall not exceed 2^32, including all IV lengths and all
41+
> instances of the authenticated encryption function with the given key.
42+
43+
Following this guideline, only 4,294,967,296 messages with random
44+
nonces can be encrypted under a given key. While this bound is high,
45+
it's possible to encounter in practice, and systems which might
46+
reach it should consider alternatives to purely random nonces, like
47+
a counter or a combination of a random nonce + counter.
48+
49+
See the [`aead-stream`] crate for a ready-made implementation of the latter.
50+
51+
[NIST SP 800-38D]: https://csrc.nist.gov/publications/detail/sp/800-38d/final
52+
[`aead-stream`]: https://docs.rs/aead-stream
1953

2054
## Minimum Supported Rust Version
2155

aead/src/dyn_aead.rs

+201
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
use inout::{InOutBuf, InOutBufReserved};
2+
3+
use crate::{Aead, Buffer, Error, Result};
4+
5+
#[cfg(feature = "alloc")]
6+
use alloc::vec::Vec;
7+
8+
mod sealed {
9+
pub trait Sealed {}
10+
}
11+
12+
/// Object-safe variant of the [`Aead`] trait.
13+
///
14+
/// This trait is implemented automaticlly for all types which implement the [`Aead`] trait.
15+
pub trait DynAead: sealed::Sealed {
16+
fn postfix_encrypt_inout<'out>(
17+
&self,
18+
nonce: &[u8],
19+
associated_data: &[u8],
20+
buffer: InOutBufReserved<'_, 'out, u8>,
21+
) -> Result<&'out mut [u8]>;
22+
23+
fn postfix_decrypt_inout<'out>(
24+
&self,
25+
nonce: &[u8],
26+
associated_data: &[u8],
27+
buffer: InOutBuf<'_, 'out, u8>,
28+
) -> Result<&'out mut [u8]>;
29+
30+
fn postfix_encrypt_inplace<'out>(
31+
&self,
32+
nonce: &[u8],
33+
associated_data: &[u8],
34+
buffer: &'out mut [u8],
35+
plaintext_len: usize,
36+
) -> Result<&'out mut [u8]>;
37+
38+
fn postfix_decrypt_inplace<'out>(
39+
&self,
40+
nonce: &[u8],
41+
associated_data: &[u8],
42+
buffer: &'out mut [u8],
43+
) -> Result<&'out mut [u8]>;
44+
45+
fn postfix_encrypt_to_buf<'out>(
46+
&self,
47+
nonce: &[u8],
48+
associated_data: &[u8],
49+
plaintext: &[u8],
50+
buffer: &'out mut [u8],
51+
) -> Result<&'out mut [u8]>;
52+
53+
fn postfix_decrypt_to_buf<'out>(
54+
&self,
55+
nonce: &[u8],
56+
associated_data: &[u8],
57+
ciphertext: &[u8],
58+
buffer: &'out mut [u8],
59+
) -> Result<&'out mut [u8]>;
60+
61+
fn encrypt_to_buffer2(
62+
&self,
63+
nonce: &[u8],
64+
associated_data: &[u8],
65+
plaintext: &[u8],
66+
buffer: &mut dyn Buffer,
67+
) -> Result<()>;
68+
69+
fn decrypt_to_buffer2(
70+
&self,
71+
nonce: &[u8],
72+
associated_data: &[u8],
73+
ciphertext: &[u8],
74+
buffer: &mut dyn Buffer,
75+
) -> Result<()>;
76+
77+
#[cfg(feature = "alloc")]
78+
fn encrypt_to_vec(
79+
&self,
80+
nonce: &[u8],
81+
associated_data: &[u8],
82+
plaintext: &[u8],
83+
) -> Result<Vec<u8>>;
84+
85+
#[cfg(feature = "alloc")]
86+
fn decrypt_to_vec(
87+
&self,
88+
nonce: &[u8],
89+
associated_data: &[u8],
90+
ciphertext: &[u8],
91+
) -> Result<Vec<u8>>;
92+
}
93+
94+
impl<T: Aead> sealed::Sealed for T {}
95+
96+
impl<T: Aead> DynAead for T {
97+
fn postfix_encrypt_inout<'out>(
98+
&self,
99+
nonce: &[u8],
100+
associated_data: &[u8],
101+
buffer: InOutBufReserved<'_, 'out, u8>,
102+
) -> Result<&'out mut [u8]> {
103+
let nonce = nonce.try_into().map_err(|_| Error)?;
104+
Aead::postfix_encrypt_inout(self, nonce, associated_data, buffer)
105+
}
106+
107+
fn postfix_decrypt_inout<'out>(
108+
&self,
109+
nonce: &[u8],
110+
associated_data: &[u8],
111+
buffer: InOutBuf<'_, 'out, u8>,
112+
) -> Result<&'out mut [u8]> {
113+
let nonce = nonce.try_into().map_err(|_| Error)?;
114+
Aead::postfix_decrypt_inout(self, nonce, associated_data, buffer)
115+
}
116+
117+
fn postfix_encrypt_inplace<'out>(
118+
&self,
119+
nonce: &[u8],
120+
associated_data: &[u8],
121+
buffer: &'out mut [u8],
122+
plaintext_len: usize,
123+
) -> Result<&'out mut [u8]> {
124+
let nonce = nonce.try_into().map_err(|_| Error)?;
125+
Aead::postfix_encrypt_inplace(self, nonce, associated_data, buffer, plaintext_len)
126+
}
127+
128+
fn postfix_decrypt_inplace<'out>(
129+
&self,
130+
nonce: &[u8],
131+
associated_data: &[u8],
132+
buffer: &'out mut [u8],
133+
) -> Result<&'out mut [u8]> {
134+
let nonce = nonce.try_into().map_err(|_| Error)?;
135+
Aead::postfix_decrypt_inplace(self, nonce, associated_data, buffer)
136+
}
137+
138+
fn postfix_encrypt_to_buf<'out>(
139+
&self,
140+
nonce: &[u8],
141+
associated_data: &[u8],
142+
plaintext: &[u8],
143+
buffer: &'out mut [u8],
144+
) -> Result<&'out mut [u8]> {
145+
let nonce = nonce.try_into().map_err(|_| Error)?;
146+
Aead::postfix_encrypt_to_buf(self, nonce, associated_data, plaintext, buffer)
147+
}
148+
149+
fn postfix_decrypt_to_buf<'out>(
150+
&self,
151+
nonce: &[u8],
152+
associated_data: &[u8],
153+
ciphertext: &[u8],
154+
buffer: &'out mut [u8],
155+
) -> Result<&'out mut [u8]> {
156+
let nonce = nonce.try_into().map_err(|_| Error)?;
157+
Aead::postfix_decrypt_to_buf(self, nonce, associated_data, ciphertext, buffer)
158+
}
159+
160+
fn encrypt_to_buffer2(
161+
&self,
162+
nonce: &[u8],
163+
aad: &[u8],
164+
msg: &[u8],
165+
buffer: &mut dyn Buffer,
166+
) -> Result<()> {
167+
let nonce = nonce.try_into().map_err(|_| Error)?;
168+
let payload = crate::Payload { aad, msg };
169+
Aead::encrypt_to_buffer(self, nonce, payload, buffer)
170+
}
171+
172+
fn decrypt_to_buffer2(
173+
&self,
174+
nonce: &[u8],
175+
aad: &[u8],
176+
msg: &[u8],
177+
buffer: &mut dyn Buffer,
178+
) -> Result<()> {
179+
let nonce = nonce.try_into().map_err(|_| Error)?;
180+
let payload = crate::Payload { aad, msg };
181+
Aead::decrypt_to_buffer(self, nonce, payload, buffer)
182+
}
183+
184+
#[cfg(feature = "alloc")]
185+
fn encrypt_to_vec(&self, nonce: &[u8], aad: &[u8], msg: &[u8]) -> Result<Vec<u8>> {
186+
let nonce = nonce.try_into().map_err(|_| Error)?;
187+
let payload = crate::Payload { aad, msg };
188+
Aead::encrypt_to_vec(self, nonce, payload)
189+
}
190+
191+
#[cfg(feature = "alloc")]
192+
fn decrypt_to_vec(&self, nonce: &[u8], aad: &[u8], msg: &[u8]) -> Result<Vec<u8>> {
193+
let nonce = nonce.try_into().map_err(|_| Error)?;
194+
let payload = crate::Payload { aad, msg };
195+
Aead::decrypt_to_vec(self, nonce, payload)
196+
}
197+
}
198+
199+
// Ensure that `DynAead` is an object-safe trait
200+
#[allow(dead_code)]
201+
fn foo(_: &dyn DynAead) {}

0 commit comments

Comments
 (0)