1#![no_std]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3#![doc = include_str!("../README.md")]
4#![doc(
5 html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
6 html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg"
7)]
8#![warn(missing_docs, rust_2018_idioms)]
9
10#![cfg_attr(all(feature = "getrandom", feature = "std"), doc = "```")]
15#![cfg_attr(not(all(feature = "getrandom", feature = "std")), doc = "```ignore")]
16#![cfg_attr(
48 all(feature = "getrandom", feature = "heapless", feature = "std"),
49 doc = "```"
50)]
51#![cfg_attr(
52 not(all(feature = "getrandom", feature = "heapless", feature = "std")),
53 doc = "```ignore"
54)]
55pub use aead::{self, AeadCore, AeadInPlace, Error, Key, KeyInit, KeySizeUser};
82
83use cipher::{
84 consts::{U0, U12, U16},
85 generic_array::GenericArray,
86 BlockCipher, BlockEncrypt, InnerIvInit, StreamCipherCore,
87};
88use polyval::{universal_hash::UniversalHash, Polyval};
89use zeroize::Zeroize;
90
91#[cfg(feature = "aes")]
93use aes::{Aes128, Aes256};
94
95pub const A_MAX: u64 = 1 << 36;
97
98pub const P_MAX: u64 = 1 << 36;
100
101pub const C_MAX: u64 = (1 << 36) + 16;
103
104pub type Nonce = GenericArray<u8, U12>;
106
107pub type Tag = GenericArray<u8, U16>;
109
110#[cfg(feature = "aes")]
112pub type Aes128GcmSiv = AesGcmSiv<Aes128>;
113
114#[cfg(feature = "aes")]
116pub type Aes256GcmSiv = AesGcmSiv<Aes256>;
117
118type Ctr32LE<Aes> = ctr::CtrCore<Aes, ctr::flavors::Ctr32LE>;
120
121#[derive(Clone)]
123pub struct AesGcmSiv<Aes> {
124 key_generating_key: Aes,
126}
127
128impl<Aes> KeySizeUser for AesGcmSiv<Aes>
129where
130 Aes: KeySizeUser,
131{
132 type KeySize = Aes::KeySize;
133}
134
135impl<Aes> KeyInit for AesGcmSiv<Aes>
136where
137 Aes: BlockCipher<BlockSize = U16> + BlockEncrypt + KeyInit,
138{
139 fn new(key_bytes: &Key<Self>) -> Self {
140 Self {
141 key_generating_key: Aes::new(key_bytes),
142 }
143 }
144}
145
146impl<Aes> From<Aes> for AesGcmSiv<Aes>
147where
148 Aes: BlockCipher<BlockSize = U16> + BlockEncrypt,
149{
150 fn from(key_generating_key: Aes) -> Self {
151 Self { key_generating_key }
152 }
153}
154
155impl<Aes> AeadCore for AesGcmSiv<Aes>
156where
157 Aes: BlockCipher<BlockSize = U16> + BlockEncrypt + KeyInit,
158{
159 type NonceSize = U12;
160 type TagSize = U16;
161 type CiphertextOverhead = U0;
162}
163
164impl<Aes> AeadInPlace for AesGcmSiv<Aes>
165where
166 Aes: BlockCipher<BlockSize = U16> + BlockEncrypt + KeyInit,
167{
168 fn encrypt_in_place_detached(
169 &self,
170 nonce: &Nonce,
171 associated_data: &[u8],
172 buffer: &mut [u8],
173 ) -> Result<Tag, Error> {
174 Cipher::<Aes>::new(&self.key_generating_key, nonce)
175 .encrypt_in_place_detached(associated_data, buffer)
176 }
177
178 fn decrypt_in_place_detached(
179 &self,
180 nonce: &Nonce,
181 associated_data: &[u8],
182 buffer: &mut [u8],
183 tag: &Tag,
184 ) -> Result<(), Error> {
185 Cipher::<Aes>::new(&self.key_generating_key, nonce).decrypt_in_place_detached(
186 associated_data,
187 buffer,
188 tag,
189 )
190 }
191}
192
193struct Cipher<Aes>
195where
196 Aes: BlockCipher<BlockSize = U16> + BlockEncrypt,
197{
198 enc_cipher: Aes,
200
201 polyval: Polyval,
203
204 nonce: Nonce,
206}
207
208impl<Aes> Cipher<Aes>
209where
210 Aes: BlockCipher<BlockSize = U16> + BlockEncrypt + KeyInit,
211{
212 pub(crate) fn new(key_generating_key: &Aes, nonce: &Nonce) -> Self {
215 let mut mac_key = polyval::Key::default();
216 let mut enc_key = GenericArray::default();
217 let mut block = cipher::Block::<Aes>::default();
218 let mut counter = 0u32;
219
220 for derived_key in &mut [mac_key.as_mut_slice(), enc_key.as_mut_slice()] {
236 for chunk in derived_key.chunks_mut(8) {
237 block[..4].copy_from_slice(&counter.to_le_bytes());
238 block[4..].copy_from_slice(nonce.as_slice());
239
240 key_generating_key.encrypt_block(&mut block);
241 chunk.copy_from_slice(&block.as_slice()[..8]);
242
243 counter += 1;
244 }
245 }
246
247 let result = Self {
248 enc_cipher: Aes::new(&enc_key),
249 polyval: Polyval::new(&mac_key),
250 nonce: *nonce,
251 };
252
253 mac_key.as_mut_slice().zeroize();
256 enc_key.as_mut_slice().zeroize();
257 block.as_mut_slice().zeroize();
258
259 result
260 }
261
262 pub(crate) fn encrypt_in_place_detached(
264 mut self,
265 associated_data: &[u8],
266 buffer: &mut [u8],
267 ) -> Result<Tag, Error> {
268 if buffer.len() as u64 > P_MAX || associated_data.len() as u64 > A_MAX {
269 return Err(Error);
270 }
271
272 self.polyval.update_padded(associated_data);
273 self.polyval.update_padded(buffer);
274
275 let tag = self.finish_tag(associated_data.len(), buffer.len());
276 init_ctr(&self.enc_cipher, &tag).apply_keystream_partial(buffer.into());
277
278 Ok(tag)
279 }
280
281 pub(crate) fn decrypt_in_place_detached(
284 mut self,
285 associated_data: &[u8],
286 buffer: &mut [u8],
287 tag: &Tag,
288 ) -> Result<(), Error> {
289 if buffer.len() as u64 > C_MAX || associated_data.len() as u64 > A_MAX {
290 return Err(Error);
291 }
292
293 self.polyval.update_padded(associated_data);
294
295 init_ctr(&self.enc_cipher, tag).apply_keystream_partial(buffer.into());
297 self.polyval.update_padded(buffer);
298
299 let expected_tag = self.finish_tag(associated_data.len(), buffer.len());
300
301 use subtle::ConstantTimeEq;
302 if expected_tag.ct_eq(tag).into() {
303 Ok(())
304 } else {
305 init_ctr(&self.enc_cipher, tag).apply_keystream_partial(buffer.into());
308 Err(Error)
309 }
310 }
311
312 fn finish_tag(&mut self, associated_data_len: usize, buffer_len: usize) -> Tag {
314 let associated_data_bits = (associated_data_len as u64) * 8;
315 let buffer_bits = (buffer_len as u64) * 8;
316
317 let mut block = polyval::Block::default();
318 block[..8].copy_from_slice(&associated_data_bits.to_le_bytes());
319 block[8..].copy_from_slice(&buffer_bits.to_le_bytes());
320 self.polyval.update(&[block]);
321
322 let mut tag = self.polyval.finalize_reset();
323
324 for (i, byte) in tag[..12].iter_mut().enumerate() {
326 *byte ^= self.nonce[i];
327 }
328
329 tag[15] &= 0x7f;
331
332 self.enc_cipher.encrypt_block(&mut tag);
333 tag
334 }
335}
336
337#[inline]
344fn init_ctr<Aes>(cipher: Aes, nonce: &cipher::Block<Aes>) -> Ctr32LE<Aes>
345where
346 Aes: BlockCipher<BlockSize = U16> + BlockEncrypt,
347{
348 let mut counter_block = *nonce;
349 counter_block[15] |= 0x80;
350 Ctr32LE::inner_iv_init(cipher, &counter_block)
351}