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
9#![cfg_attr(feature = "getrandom", doc = "```")]
14#![cfg_attr(not(feature = "getrandom"), doc = "```ignore")]
15#![cfg_attr(all(feature = "getrandom", feature = "arrayvec"), doc = "```")]
54#![cfg_attr(
55 not(all(feature = "getrandom", feature = "arrayvec")),
56 doc = "```ignore"
57)]
58pub use aead::{self, AeadCore, AeadInOut, Error, Key, KeyInit, KeySizeUser};
87
88#[cfg(feature = "aes")]
89pub use aes;
90
91use aead::{TagPosition, inout::InOutBuf};
92use cipher::{
93 BlockCipherEncrypt, BlockSizeUser, InnerIvInit, StreamCipherCore,
94 array::Array,
95 consts::{U12, U16},
96};
97use core::fmt;
98use polyval::{Polyval, universal_hash::UniversalHash};
99
100#[cfg(feature = "aes")]
102use aes::{Aes128, Aes256};
103
104pub const A_MAX: u64 = 1 << 36;
106
107pub const P_MAX: u64 = 1 << 36;
109
110pub const C_MAX: u64 = (1 << 36) + 16;
112
113pub type Nonce = Array<u8, U12>;
115
116pub type Tag = Array<u8, U16>;
118
119#[cfg(feature = "aes")]
121pub type Aes128GcmSiv = AesGcmSiv<Aes128>;
122
123#[cfg(feature = "aes")]
125pub type Aes256GcmSiv = AesGcmSiv<Aes256>;
126
127type Ctr32LE<Aes> = ctr::CtrCore<Aes, ctr::flavors::Ctr32LE>;
129
130#[derive(Clone)]
132pub struct AesGcmSiv<Aes> {
133 key_generating_key: Aes,
135}
136
137impl<Aes> KeySizeUser for AesGcmSiv<Aes>
138where
139 Aes: KeySizeUser,
140{
141 type KeySize = Aes::KeySize;
142}
143
144impl<Aes> KeyInit for AesGcmSiv<Aes>
145where
146 Aes: BlockSizeUser<BlockSize = U16> + BlockCipherEncrypt + KeyInit,
147{
148 fn new(key_bytes: &Key<Self>) -> Self {
149 Self {
150 key_generating_key: Aes::new(key_bytes),
151 }
152 }
153}
154
155impl<Aes> From<Aes> for AesGcmSiv<Aes>
156where
157 Aes: BlockSizeUser<BlockSize = U16> + BlockCipherEncrypt,
158{
159 fn from(key_generating_key: Aes) -> Self {
160 Self { key_generating_key }
161 }
162}
163
164impl<Aes> AeadCore for AesGcmSiv<Aes>
165where
166 Aes: BlockSizeUser<BlockSize = U16> + BlockCipherEncrypt + KeyInit,
167{
168 type NonceSize = U12;
169 type TagSize = U16;
170 const TAG_POSITION: TagPosition = TagPosition::Postfix;
171}
172
173impl<Aes> AeadInOut for AesGcmSiv<Aes>
174where
175 Aes: BlockSizeUser<BlockSize = U16> + BlockCipherEncrypt + KeyInit,
176{
177 fn encrypt_inout_detached(
178 &self,
179 nonce: &Nonce,
180 associated_data: &[u8],
181 buffer: InOutBuf<'_, '_, u8>,
182 ) -> Result<Tag, Error> {
183 Cipher::<Aes>::new(&self.key_generating_key, nonce)
184 .encrypt_inout_detached(associated_data, buffer)
185 }
186
187 fn decrypt_inout_detached(
188 &self,
189 nonce: &Nonce,
190 associated_data: &[u8],
191 buffer: InOutBuf<'_, '_, u8>,
192 tag: &Tag,
193 ) -> Result<(), Error> {
194 Cipher::<Aes>::new(&self.key_generating_key, nonce).decrypt_inout_detached(
195 associated_data,
196 buffer,
197 tag,
198 )
199 }
200}
201
202impl<Aes> fmt::Debug for AesGcmSiv<Aes> {
203 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
204 f.debug_struct("AesGcmSiv").finish_non_exhaustive()
205 }
206}
207
208struct Cipher<Aes>
210where
211 Aes: BlockSizeUser<BlockSize = U16> + BlockCipherEncrypt,
212{
213 enc_cipher: Aes,
215
216 polyval: Polyval,
218
219 nonce: Nonce,
221}
222
223impl<Aes> Cipher<Aes>
224where
225 Aes: BlockSizeUser<BlockSize = U16> + BlockCipherEncrypt + KeyInit,
226{
227 pub(crate) fn new(key_generating_key: &Aes, nonce: &Nonce) -> Self {
230 let mut mac_key = polyval::Key::default();
231 let mut enc_key = Array::default();
232 let mut block = cipher::Block::<Aes>::default();
233 let mut counter = 0u32;
234
235 for derived_key in &mut [mac_key.as_mut_slice(), enc_key.as_mut_slice()] {
251 for chunk in derived_key.chunks_mut(8) {
252 block[..4].copy_from_slice(&counter.to_le_bytes());
253 block[4..].copy_from_slice(nonce.as_slice());
254
255 key_generating_key.encrypt_block(&mut block);
256 chunk.copy_from_slice(&block.as_slice()[..8]);
257
258 counter += 1;
259 }
260 }
261
262 let result = Self {
263 enc_cipher: Aes::new(&enc_key),
264 polyval: Polyval::new(&mac_key),
265 nonce: *nonce,
266 };
267
268 #[cfg(feature = "zeroize")]
271 {
272 use zeroize::Zeroize;
273 mac_key.as_mut_slice().zeroize();
274 enc_key.as_mut_slice().zeroize();
275 block.as_mut_slice().zeroize();
276 }
277
278 result
279 }
280
281 pub(crate) fn encrypt_inout_detached(
283 mut self,
284 associated_data: &[u8],
285 buffer: InOutBuf<'_, '_, u8>,
286 ) -> Result<Tag, Error> {
287 if buffer.len() as u64 > P_MAX || associated_data.len() as u64 > A_MAX {
288 return Err(Error);
289 }
290
291 self.polyval.update_padded(associated_data);
292 self.polyval.update_padded(buffer.get_in());
293
294 let tag = self.finish_tag(associated_data.len(), buffer.len());
295 init_ctr(&self.enc_cipher, &tag).apply_keystream_partial(buffer);
296
297 Ok(tag)
298 }
299
300 pub(crate) fn decrypt_inout_detached(
303 mut self,
304 associated_data: &[u8],
305 mut buffer: InOutBuf<'_, '_, u8>,
306 tag: &Tag,
307 ) -> Result<(), Error> {
308 if buffer.len() as u64 > C_MAX || associated_data.len() as u64 > A_MAX {
309 return Err(Error);
310 }
311
312 self.polyval.update_padded(associated_data);
313
314 init_ctr(&self.enc_cipher, tag).apply_keystream_partial(buffer.reborrow());
316 self.polyval.update_padded(buffer.get_out());
317
318 let expected_tag = self.finish_tag(associated_data.len(), buffer.len());
319
320 use ctutils::CtEq;
321 if expected_tag.ct_eq(tag).into() {
322 Ok(())
323 } else {
324 init_ctr(&self.enc_cipher, tag).apply_keystream_partial(buffer);
327 Err(Error)
328 }
329 }
330
331 fn finish_tag(&mut self, associated_data_len: usize, buffer_len: usize) -> Tag {
333 let associated_data_bits = (associated_data_len as u64) * 8;
334 let buffer_bits = (buffer_len as u64) * 8;
335
336 let mut block = polyval::Block::default();
337 block[..8].copy_from_slice(&associated_data_bits.to_le_bytes());
338 block[8..].copy_from_slice(&buffer_bits.to_le_bytes());
339 self.polyval.update(&[block]);
340
341 let mut tag = self.polyval.finalize_reset();
342
343 for (i, byte) in tag[..12].iter_mut().enumerate() {
345 *byte ^= self.nonce[i];
346 }
347
348 tag[15] &= 0x7f;
350
351 self.enc_cipher.encrypt_block(&mut tag);
352 tag
353 }
354}
355
356#[inline]
363fn init_ctr<Aes>(cipher: Aes, nonce: &cipher::Block<Aes>) -> Ctr32LE<Aes>
364where
365 Aes: BlockSizeUser<BlockSize = U16> + BlockCipherEncrypt,
366{
367 let mut counter_block = *nonce;
368 counter_block[15] |= 0x80;
369 Ctr32LE::inner_iv_init(cipher, &counter_block)
370}