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