1use super::*;
2use crate::{Aead, AeadError, Bytes, Hash};
3
4#[cfg_attr(feature = "zeroize", derive(zeroize::Zeroize, zeroize::ZeroizeOnDrop))]
41pub struct AsconAead128 {
42 iv: u64,
43 k0: u64,
44 k1: u64,
45 key: [u8; 16],
46}
47
48impl AsconAead128 {
49 pub fn new(key: &[u8; 16]) -> Self {
51 let k0 = u64::from_le_bytes(key[0..8].try_into().unwrap());
52 let k1 = u64::from_le_bytes(key[8..16].try_into().unwrap());
53 AsconAead128 {
54 iv: 0x0000_1000_808c_0001,
55 k0,
56 k1,
57 key: *key,
58 }
59 }
60
61 fn init_state(&self, nonce: &[u8; 16]) -> State {
63 let mut state = State::init_aead(&self.key, nonce, self.iv);
64 p12(&mut state);
65 state.xor_word(3, self.k0);
66 state.xor_word(4, self.k1);
67 state
68 }
69
70 fn process_ad(state: &mut State, aad: &[u8]) {
72 if aad.is_empty() {
73 return;
74 }
75 let mut chunks = aad.chunks_exact(16);
76 for chunk in &mut chunks {
77 state.xor_rate128_bytes(chunk.try_into().unwrap());
78 p8(state);
79 }
80 let remainder = chunks.remainder();
81 if !remainder.is_empty() {
82 state.xor_partial_rate(remainder);
83 }
84 state.apply_aead_pad(remainder.len());
85 p8(state);
86 }
87
88 fn compute_tag(&self, state: &State) -> [u8; 16] {
90 let tag = state.tag_bytes();
91 let t0 = u64::from_le_bytes(tag[0..8].try_into().unwrap()) ^ self.k0;
92 let t1 = u64::from_le_bytes(tag[8..16].try_into().unwrap()) ^ self.k1;
93 let mut result = [0u8; 16];
94 result[..8].copy_from_slice(&t0.to_le_bytes());
95 result[8..].copy_from_slice(&t1.to_le_bytes());
96 result
97 }
98}
99
100impl Aead for AsconAead128 {
101 const TAG_SIZE: usize = 16;
102 const NONCE_SIZE: usize = 16;
103
104 fn encrypt_in_place(&self, in_out: &mut [u8], nonce: &[u8], aad: &[u8]) -> Hash {
105 let nonce: &[u8; 16] = nonce.try_into().expect("nonce must be 16 bytes");
106 let mut state = self.init_state(nonce);
107 Self::process_ad(&mut state, aad);
108 state.apply_domain_sep();
109
110 let rem_len = in_out.len() % 16;
111
112 let mut chunks = in_out.chunks_exact_mut(16);
113 for chunk in &mut chunks {
114 state.encrypt_in_place_block(chunk.try_into().unwrap());
115 p8(&mut state);
116 }
117 let remainder = chunks.into_remainder();
118
119 if rem_len > 0 {
120 state.xor_partial_rate(remainder);
121 state.read_rate_bytes(remainder);
122 }
123 state.apply_aead_pad(rem_len);
124
125 state.xor_word(2, self.k0);
126 state.xor_word(3, self.k1);
127 p12(&mut state);
128
129 let tag_bytes = self.compute_tag(&state);
130 let mut tag = Hash(Bytes::<64>::with_length(16));
131 tag.as_mut().copy_from_slice(&tag_bytes);
132 tag
133 }
134
135 fn decrypt_in_place(&self, in_out: &mut [u8], nonce: &[u8], aad: &[u8], tag: &[u8]) -> Result<(), AeadError> {
136 if tag.len() != Self::TAG_SIZE {
137 return Err(AeadError::InvalidCiphertext);
138 }
139 let nonce: &[u8; 16] = nonce.try_into().map_err(|_| AeadError::InvalidNonce)?;
140
141 let mut state = self.init_state(nonce);
142 Self::process_ad(&mut state, aad);
143 state.apply_domain_sep();
144
145 let rem_len = in_out.len() % 16;
146
147 let mut chunks = in_out.chunks_exact_mut(16);
148 for chunk in &mut chunks {
149 state.decrypt_in_place_block(chunk.try_into().unwrap());
150 p8(&mut state);
151 }
152 let remainder = chunks.into_remainder();
153
154 if rem_len > 0 {
155 let mut ct = [0u8; 16];
156 ct[..rem_len].copy_from_slice(remainder);
157 state.read_rate_bytes(remainder);
158 for j in 0..rem_len {
159 remainder[j] ^= ct[j];
160 }
161 state.apply_aead_pad(rem_len);
162 state.write_rate_bytes(&ct[..rem_len]);
163 } else {
164 state.apply_aead_pad(0);
165 }
166
167 state.xor_word(2, self.k0);
168 state.xor_word(3, self.k1);
169 p12(&mut state);
170
171 let computed = self.compute_tag(&state);
172
173 if !constant_time_eq::constant_time_eq(&computed, tag) {
174 in_out.fill(0);
175 return Err(AeadError::InvalidCiphertext);
176 }
177
178 Ok(())
179 }
180}
181
182#[cfg(test)]
183mod tests {
184 use super::*;
185 use crate::Aead;
186
187 static KEY: [u8; 16] = [
188 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
189 ];
190 static NONCE: [u8; 16] = [
191 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
192 ];
193
194 #[test]
195 fn empty_pt_empty_ad() {
196 let ae = AsconAead128::new(&KEY);
197 let mut pt = vec![];
198 let tag = ae.encrypt_in_place(&mut pt, &NONCE, &[]);
199 let expected_ct = hex::decode("").unwrap();
200 let expected_tag = hex::decode("4F9C278211BEC9316BF68F46EE8B2EC6").unwrap();
201 assert_eq!(pt, expected_ct);
202 assert_eq!(tag.as_ref(), expected_tag.as_slice());
203 }
204
205 #[test]
206 fn one_byte_pt_empty_ad() {
207 let ae = AsconAead128::new(&KEY);
208 let mut pt = hex::decode("20").unwrap();
209 let tag = ae.encrypt_in_place(&mut pt, &NONCE, &[]);
210 let expected_ct = hex::decode("E8").unwrap();
213 let expected_tag = hex::decode("DD576ABA1CD3E6FC704DE02AEDB79588").unwrap();
214 assert_eq!(pt, expected_ct);
215 assert_eq!(tag.as_ref(), expected_tag.as_slice());
216 }
217
218 #[test]
219 fn one_byte_pt_one_byte_ad() {
220 let ae = AsconAead128::new(&KEY);
221 let mut pt = hex::decode("20").unwrap();
222 let aad = hex::decode("30").unwrap();
223 let tag = ae.encrypt_in_place(&mut pt, &NONCE, &aad);
224 let expected_ct = hex::decode("96").unwrap();
226 let expected_tag = hex::decode("2B8016836C75A7D86866588CA245D886").unwrap();
227 assert_eq!(pt, expected_ct);
228 assert_eq!(tag.as_ref(), expected_tag.as_slice());
229 }
230
231 #[test]
232 fn two_byte_pt_six_byte_ad() {
233 let ae = AsconAead128::new(&KEY);
234 let mut pt = hex::decode("2021").unwrap();
235 let aad = hex::decode("303132333435").unwrap();
236 let tag = ae.encrypt_in_place(&mut pt, &NONCE, &aad);
237 let expected_ct = hex::decode("9310").unwrap();
239 let expected_tag = hex::decode("6848C186CA92DCC20741A92F7AAFE673").unwrap();
240 assert_eq!(pt, expected_ct);
241 assert_eq!(tag.as_ref(), expected_tag.as_slice());
242 }
243
244 #[test]
245 fn thirtytwo_byte_pt_twentysix_byte_ad() {
246 let ae = AsconAead128::new(&KEY);
247 let mut pt = hex::decode("202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F").unwrap();
248 let aad = hex::decode("303132333435363738393A3B3C3D3E3F40414243444546474849").unwrap();
249 let tag = ae.encrypt_in_place(&mut pt, &NONCE, &aad);
250 let expected_ct = hex::decode("A92EF70DF2EF0FAA74A21F9739FB89237DF62F9A2B4080B850046DDD386DED48").unwrap();
252 let expected_tag = hex::decode("E7833CF56F755945AEB70D2BAAAA361C").unwrap();
253 assert_eq!(pt, expected_ct);
254 assert_eq!(tag.as_ref(), expected_tag.as_slice());
255 }
256
257 #[test]
258 fn roundtrip() {
259 let key = [0x55u8; 16];
260 let nonce = [0xAAu8; 16];
261 let aad = b"associated data";
262 let plaintext = b"hello, world!";
263
264 let ae = AsconAead128::new(&key);
265 let mut ct = plaintext.to_vec();
266 let tag = ae.encrypt_in_place(&mut ct, &nonce, aad);
267
268 let mut decrypted = ct.clone();
269 ae.decrypt_in_place(&mut decrypted, &nonce, aad, tag.as_ref()).unwrap();
270 assert_eq!(decrypted, plaintext);
271 }
272
273 #[test]
274 fn roundtrip_empty() {
275 let key = [0x55u8; 16];
276 let nonce = [0xAAu8; 16];
277
278 let ae = AsconAead128::new(&key);
279 let mut ct = vec![];
280 let tag = ae.encrypt_in_place(&mut ct, &nonce, b"ad");
281
282 let mut decrypted = ct.clone();
283 ae.decrypt_in_place(&mut decrypted, &nonce, b"ad", tag.as_ref())
284 .unwrap();
285 assert!(decrypted.is_empty());
286 }
287
288 #[test]
289 fn tampered_tag_fails() {
290 let key = [0x55u8; 16];
291 let nonce = [0xAAu8; 16];
292
293 let ae = AsconAead128::new(&key);
294 let mut ct = b"secret".to_vec();
295 let mut tag = ae.encrypt_in_place(&mut ct, &nonce, b"");
296 tag.as_mut()[0] ^= 1;
297
298 let mut decrypted = ct.clone();
299 let result = ae.decrypt_in_place(&mut decrypted, &nonce, b"", tag.as_ref());
300 assert!(result.is_err());
301 assert!(decrypted.iter().all(|b| *b == 0));
302 }
303
304 #[test]
305 fn tampered_ciphertext_fails() {
306 let key = [0x55u8; 16];
307 let nonce = [0xAAu8; 16];
308
309 let ae = AsconAead128::new(&key);
310 let mut ct = b"secret".to_vec();
311 let tag = ae.encrypt_in_place(&mut ct, &nonce, b"");
312 ct[3] ^= 1;
313
314 let mut decrypted = ct.clone();
315 let result = ae.decrypt_in_place(&mut decrypted, &nonce, b"", tag.as_ref());
316 assert!(result.is_err());
317 }
318
319 #[test]
320 fn wrong_nonce_fails() {
321 let key = [0x55u8; 16];
322
323 let ae = AsconAead128::new(&key);
324 let mut ct = b"secret".to_vec();
325 let tag = ae.encrypt_in_place(&mut ct, &[0u8; 16], b"");
326 let mut decrypted = ct.clone();
327 let result = ae.decrypt_in_place(&mut decrypted, &[1u8; 16], b"", tag.as_ref());
328 assert!(result.is_err());
329 }
330
331 #[test]
332 fn wrong_ad_fails() {
333 let key = [0x55u8; 16];
334 let nonce = [0xAAu8; 16];
335
336 let ae = AsconAead128::new(&key);
337 let mut ct = b"secret".to_vec();
338 let tag = ae.encrypt_in_place(&mut ct, &nonce, b"correct ad");
339 let mut decrypted = ct.clone();
340 let result = ae.decrypt_in_place(&mut decrypted, &nonce, b"wrong ad", tag.as_ref());
341 assert!(result.is_err());
342 }
343
344 #[test]
345 fn wrong_key_fails() {
346 let nonce = [0xAAu8; 16];
347
348 let ae = AsconAead128::new(&[0x55u8; 16]);
349 let mut ct = b"secret".to_vec();
350 let tag = ae.encrypt_in_place(&mut ct, &nonce, b"");
351 let mut decrypted = ct.clone();
352 let ae2 = AsconAead128::new(&[0xAAu8; 16]);
353 let result = ae2.decrypt_in_place(&mut decrypted, &nonce, b"", tag.as_ref());
354 assert!(result.is_err());
355 }
356
357 #[test]
358 fn empty_ad_with_data() {
359 let key = [0x55u8; 16];
360 let nonce = [0xAAu8; 16];
361
362 let ae = AsconAead128::new(&key);
363 let mut ct = b"data with empty AD".to_vec();
364 let tag = ae.encrypt_in_place(&mut ct, &nonce, b"");
365
366 let mut decrypted = ct.clone();
367 ae.decrypt_in_place(&mut decrypted, &nonce, b"", tag.as_ref()).unwrap();
368 assert_eq!(decrypted, b"data with empty AD");
369 }
370
371 #[test]
372 fn kat_vectors() {
373 let data = include_str!("../../testdata/ascon/LWC_AEAD_KAT_128_128.txt");
374 let mut count = 0u64;
375 let mut key = None;
376 let mut nonce = None;
377 let mut pt_hex = String::new();
378 let mut ad_hex = String::new();
379 let mut ct_hex = String::new();
380
381 for line in data.lines() {
382 let line = line.trim();
383 if line.is_empty() {
384 if let (Some(k), Some(n)) = (&key, &nonce) {
385 let key_bytes: [u8; 16] = hex::decode(k).unwrap().try_into().unwrap();
386 let nonce_bytes: [u8; 16] = hex::decode(n).unwrap().try_into().unwrap();
387 let pt = hex::decode(&pt_hex).unwrap();
388 let ct_bytes = hex::decode(&ct_hex).unwrap();
389 let aad = hex::decode(&ad_hex).unwrap();
390
391 let expected_ct = &ct_bytes[..pt.len()];
392 let expected_tag = &ct_bytes[pt.len()..];
393
394 let ae = AsconAead128::new(&key_bytes);
395 let mut enc = pt.clone();
396 let tag = ae.encrypt_in_place(&mut enc, &nonce_bytes, &aad);
397 assert_eq!(enc, expected_ct, "KAT AEAD Count={count} ct mismatch");
398 assert_eq!(tag.as_ref(), expected_tag, "KAT AEAD Count={count} tag mismatch");
399
400 let mut dec = expected_ct.to_vec();
401 ae.decrypt_in_place(&mut dec, &nonce_bytes, &aad, expected_tag)
402 .unwrap_or_else(|e| panic!("KAT AEAD Count={count} decrypt failed: {e:?}"));
403 assert_eq!(dec, pt, "KAT AEAD Count={count} decrypt pt mismatch");
404 }
405 key = None;
407 nonce = None;
408 pt_hex.clear();
409 ad_hex.clear();
410 ct_hex.clear();
411 continue;
412 }
413
414 if line.starts_with("Count = ") {
415 count = line["Count = ".len()..].parse().unwrap();
416 continue;
417 }
418 if line.starts_with("Key = ") {
419 key = Some(line[6..].to_string());
420 continue;
421 }
422 if line.starts_with("Nonce = ") {
423 nonce = Some(line[8..].to_string());
424 continue;
425 }
426 if line.starts_with("PT = ") {
427 pt_hex = line[5..].to_string();
428 continue;
429 }
430 if line.starts_with("AD = ") {
431 ad_hex = line[5..].to_string();
432 continue;
433 }
434 if line.starts_with("CT = ") {
435 ct_hex = line[5..].to_string();
436 continue;
437 }
438 }
439
440 if let (Some(k), Some(n)) = (&key, &nonce) {
442 let key_bytes: [u8; 16] = hex::decode(k).unwrap().try_into().unwrap();
443 let nonce_bytes: [u8; 16] = hex::decode(n).unwrap().try_into().unwrap();
444 let pt = hex::decode(&pt_hex).unwrap();
445 let ct_bytes = hex::decode(&ct_hex).unwrap();
446 let aad = hex::decode(&ad_hex).unwrap();
447
448 let expected_ct = &ct_bytes[..pt.len()];
449 let expected_tag = &ct_bytes[pt.len()..];
450
451 let ae = AsconAead128::new(&key_bytes);
452 let mut enc = pt.clone();
453 let tag = ae.encrypt_in_place(&mut enc, &nonce_bytes, &aad);
454 assert_eq!(enc, expected_ct, "KAT AEAD Count={count} ct mismatch");
455 assert_eq!(tag.as_ref(), expected_tag, "KAT AEAD Count={count} tag mismatch");
456
457 let mut dec = expected_ct.to_vec();
458 ae.decrypt_in_place(&mut dec, &nonce_bytes, &aad, expected_tag)
459 .unwrap_or_else(|e| panic!("KAT AEAD Count={count} decrypt failed: {e:?}"));
460 assert_eq!(dec, pt, "KAT AEAD Count={count} decrypt pt mismatch");
461 }
462 }
463}