1use crate::aes::Aes128;
29
30fn validate_params(nonce_len: usize, tag_len: usize) -> Result<usize, crate::Error> {
39 if !(7..=13).contains(&nonce_len) || !(4..=16).contains(&tag_len) || !tag_len.is_multiple_of(2)
40 {
41 return Err(crate::Error::InvalidInput);
42 }
43 Ok(15 - nonce_len)
44}
45
46fn b0_flags(tag_len: usize, has_aad: bool, l: usize) -> u8 {
49 ((((tag_len - 2) / 2) << 3) | (u8::from(has_aad) << 6) as usize | (l - 1)) as u8
50}
51
52fn check_length_domain(l: usize, pt_len: usize, aad_len: usize) -> Result<(), crate::Error> {
56 if l < 8 && pt_len >= 1usize << (8 * l) {
57 return Err(crate::Error::InvalidInput);
58 }
59 if aad_len >= 0xff00 {
60 return Err(crate::Error::InvalidInput);
61 }
62 Ok(())
63}
64
65fn ctr_raw(nonce: &[u8], l: usize, counter: u32) -> [u8; 16] {
68 debug_assert!(1 + nonce.len() + l == 16);
69 let mut block = [0u8; 16];
70 block[0] = l as u8 - 1;
71 block[1..1 + nonce.len()].copy_from_slice(nonce);
72 let ctr = counter as u64;
73 for i in 0..l {
74 block[16 - l + i] = (ctr >> (8 * (l - 1 - i))) as u8;
75 }
76 block
77}
78
79fn ctr_block(aes: &Aes128, nonce: &[u8], l: usize, counter: u32) -> [u8; 16] {
80 let mut block = ctr_raw(nonce, l, counter);
81 aes.encrypt_block(&mut block);
82 block
83}
84
85fn ctr_xor(aes: &Aes128, nonce: &[u8], l: usize, start: u32, data: &[u8]) -> Vec<u8> {
88 let mut out = vec![0u8; data.len()];
89 let mut counter = start;
90 let mut ks = [0u8; crate::aes::CTR_BATCH_BLOCKS * 16];
91 for (in_chunk, out_chunk) in data
92 .chunks(crate::aes::CTR_BATCH_BLOCKS * 16)
93 .zip(out.chunks_mut(crate::aes::CTR_BATCH_BLOCKS * 16))
94 {
95 let n = in_chunk.len().div_ceil(16);
96 aes.encrypt_ctr_batch(ctr_raw(nonce, l, counter), n, &mut ks);
97 let ks_slice = &ks[..out_chunk.len()];
98 for (o, (b, k)) in out_chunk.iter_mut().zip(in_chunk.iter().zip(ks_slice)) {
99 *o = b ^ k;
100 }
101 counter = counter.wrapping_add(n as u32);
102 }
103 out
104}
105
106fn cbc_mac(
108 aes: &Aes128,
109 nonce: &[u8],
110 l: usize,
111 tag_len: usize,
112 aad: &[u8],
113 pt: &[u8],
114) -> [u8; 16] {
115 let mut buf: Vec<u8> = Vec::with_capacity(16 + aad.len() + pt.len() + 32);
116 buf.push(b0_flags(tag_len, !aad.is_empty(), l));
120 buf.extend_from_slice(nonce);
121 let plen = pt.len() as u64;
124 for i in (0..l).rev() {
125 buf.push((plen >> (8 * i)) as u8);
126 }
127
128 if !aad.is_empty() {
133 buf.extend_from_slice(&(aad.len() as u16).to_be_bytes());
134 buf.extend_from_slice(aad);
135 let rem = buf.len() % 16;
136 if rem != 0 {
137 buf.resize(buf.len() + 16 - rem, 0);
138 }
139 }
140
141 buf.extend_from_slice(pt);
142
143 let mut t = [0u8; 16];
144 for chunk in buf.chunks(16) {
145 let mut block = [0u8; 16];
146 block[..chunk.len()].copy_from_slice(chunk);
147 for i in 0..16 {
148 block[i] ^= t[i];
149 }
150 aes.encrypt_block(&mut block);
151 t = block;
152 }
153 t
154}
155
156fn tag_finish(t: &mut [u8; 16], s0: &[u8; 16], tag_len: usize) {
159 for i in 0..tag_len {
160 t[i] ^= s0[i];
161 }
162}
163
164fn seal_core(
165 aes: &Aes128,
166 nonce: &[u8],
167 tag_len: usize,
168 aad: &[u8],
169 plaintext: &[u8],
170) -> Result<Vec<u8>, crate::Error> {
171 let l = validate_params(nonce.len(), tag_len)?;
172 check_length_domain(l, plaintext.len(), aad.len())?;
173 let mut t = cbc_mac(aes, nonce, l, tag_len, aad, plaintext);
174 let ct = ctr_xor(aes, nonce, l, 1, plaintext);
175 let s0 = ctr_block(aes, nonce, l, 0);
176 tag_finish(&mut t, &s0, tag_len);
177 let mut out = ct;
178 out.extend_from_slice(&t[..tag_len]);
179 Ok(out)
180}
181
182fn open_core(
183 aes: &Aes128,
184 nonce: &[u8],
185 tag_len: usize,
186 aad: &[u8],
187 ct_and_tag: &[u8],
188) -> Result<Vec<u8>, crate::Error> {
189 let l = validate_params(nonce.len(), tag_len)?;
190 if ct_and_tag.len() < tag_len {
191 return Err(crate::Error::VerificationFailed);
192 }
193 if l < 8 && ct_and_tag.len() - tag_len >= 1usize << (8 * l) {
196 return Err(crate::Error::VerificationFailed);
197 }
198 let split = ct_and_tag.len() - tag_len;
199 let (ct, tag) = ct_and_tag.split_at(split);
200
201 let pt = ctr_xor(aes, nonce, l, 1, ct);
202 let mut t = cbc_mac(aes, nonce, l, tag_len, aad, &pt);
203 let s0 = ctr_block(aes, nonce, l, 0);
204 tag_finish(&mut t, &s0, tag_len);
205 crate::ct::verify_tag(&t[..tag_len], tag)?;
206 Ok(pt)
207}
208
209#[derive(Clone)]
219pub struct Aes128CcmAny {
220 aes: Aes128,
221 tag_len: usize,
222}
223
224impl Aes128CcmAny {
225 pub const KEY_LEN: usize = 16;
227
228 pub const APPROVAL: crate::Approval = crate::Approval::Approved;
231
232 pub fn new(key: &[u8; 16], tag_len: usize) -> Result<Self, crate::Error> {
235 if !(4..=16).contains(&tag_len) || !tag_len.is_multiple_of(2) {
236 return Err(crate::Error::InvalidInput);
237 }
238 Ok(Self {
239 aes: Aes128::new(key),
240 tag_len,
241 })
242 }
243
244 pub fn seal(
248 &self,
249 nonce: &[u8],
250 aad: &[u8],
251 plaintext: &[u8],
252 ) -> Result<Vec<u8>, crate::Error> {
253 seal_core(&self.aes, nonce, self.tag_len, aad, plaintext)
254 }
255
256 pub fn open(
259 &self,
260 nonce: &[u8],
261 aad: &[u8],
262 ct_and_tag: &[u8],
263 ) -> Result<Vec<u8>, crate::Error> {
264 open_core(&self.aes, nonce, self.tag_len, aad, ct_and_tag)
265 }
266}
267
268impl std::fmt::Debug for Aes128CcmAny {
269 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
270 f.debug_struct("Aes128CcmAny")
271 .field("tag_len", &self.tag_len)
272 .finish()
273 }
274}
275
276macro_rules! ccm_impl {
283 ($name:ident, $nonce_len:expr, $tag_len:expr, $doc:expr) => {
284 #[doc = $doc]
285 #[derive(Clone)]
286 pub struct $name {
287 any: Aes128CcmAny,
288 }
289
290 impl $name {
291 pub const KEY_LEN: usize = 16;
293 pub const NONCE_LEN: usize = $nonce_len;
295 pub const TAG_LEN: usize = $tag_len;
297
298 pub const APPROVAL: crate::Approval = crate::Approval::Approved;
300
301 pub fn new(key: &[u8; 16]) -> Self {
303 Self {
304 any: Aes128CcmAny::new(key, $tag_len).expect("fixed parameter set"),
306 }
307 }
308
309 pub fn seal(
316 &self,
317 nonce: &[u8; $nonce_len],
318 aad: &[u8],
319 plaintext: &[u8],
320 ) -> Result<Vec<u8>, crate::Error> {
321 self.any.seal(nonce, aad, plaintext)
322 }
323
324 pub fn open(
327 &self,
328 nonce: &[u8; $nonce_len],
329 aad: &[u8],
330 ct_and_tag: &[u8],
331 ) -> Result<Vec<u8>, crate::Error> {
332 self.any.open(nonce, aad, ct_and_tag)
333 }
334 }
335
336 impl std::fmt::Debug for $name {
337 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
338 f.write_str(stringify!($name))
339 }
340 }
341 };
342}
343
344ccm_impl!(
345 Aes128Ccm,
346 13,
347 16,
348 "AES-128-CCM 实例(M=16,13 字节 nonce,L=2)。"
349);
350ccm_impl!(
351 Aes128CcmTls,
352 12,
353 16,
354 "AES-128-CCM 实例(M=16,12 字节 nonce,L=3)——RFC 8446 §B.5 TLS 1.3 参数集。"
355);
356ccm_impl!(
357 Aes128Ccm8Tls,
358 12,
359 8,
360 "AES-128-CCM 实例(M=8,12 字节 nonce,L=3)——RFC 8446 §B.5 的 \
361 AEAD_AES_128_CCM_8;8 字节标签不在 SP 800-52r2 TLS 批准套件面。"
362);
363
364#[cfg(test)]
365mod tests {
366 use super::*;
367
368 #[test]
369 fn round_trip_and_tamper() {
370 let key = [0x07u8; 16];
371 let nonce13 = [
372 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c,
373 ];
374 let aead = Aes128Ccm::new(&key);
375
376 for len in [0usize, 1, 15, 16, 17, 33, 64] {
377 let pt: Vec<u8> = (0..len).map(|i| i as u8).collect();
378 let sealed = aead.seal(&nonce13, b"aad", &pt).unwrap();
379 assert_eq!(sealed.len(), len + 16);
380 let opened = aead.open(&nonce13, b"aad", &sealed).expect("round trip");
381 assert_eq!(opened, pt, "len {len}");
382 }
383
384 let sealed = aead.seal(&nonce13, b"aad", b"hello ccm").unwrap();
385 let mut bad = sealed.clone();
386 let last = bad.len() - 1;
387 bad[last] ^= 1;
388 assert_eq!(
389 aead.open(&nonce13, b"aad", &bad),
390 Err(crate::Error::VerificationFailed)
391 );
392 assert_eq!(
393 aead.open(&nonce13, b"bad", &sealed),
394 Err(crate::Error::VerificationFailed)
395 );
396
397 let nonce12 = [
399 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
400 ];
401 let tls = Aes128CcmTls::new(&key);
402 for len in [0usize, 1, 15, 16, 17, 33, 64] {
403 let pt: Vec<u8> = (0..len).map(|i| i as u8).collect();
404 let sealed = tls.seal(&nonce12, b"aad", &pt).unwrap();
405 assert_eq!(sealed.len(), len + 16);
406 let opened = tls.open(&nonce12, b"aad", &sealed).expect("round trip");
407 assert_eq!(opened, pt, "tls len {len}");
408 }
409 assert_ne!(
411 aead.seal(&nonce13, b"aad", b"x").unwrap(),
412 tls.seal(&nonce12, b"aad", b"x").unwrap()
413 );
414
415 let ccm8 = Aes128Ccm8Tls::new(&key);
417 let any8 = Aes128CcmAny::new(&key, 8).unwrap();
418 for len in [0usize, 1, 15, 16, 17, 33, 64] {
419 let pt: Vec<u8> = (0..len).map(|i| i as u8).collect();
420 let sealed = ccm8.seal(&nonce12, b"aad", &pt).unwrap();
421 assert_eq!(sealed.len(), len + 8);
422 let opened = ccm8.open(&nonce12, b"aad", &sealed).expect("round trip");
423 assert_eq!(opened, pt, "ccm8 len {len}");
424 assert_eq!(
425 sealed,
426 any8.seal(nonce12.as_slice(), b"aad", &pt).unwrap(),
427 "fixed Ccm8Tls must match Any(M=8), len {len}"
428 );
429 }
430
431 let big = vec![0u8; 1 << 16];
435 assert_eq!(
436 aead.seal(&nonce13, b"", &big),
437 Err(crate::Error::InvalidInput)
438 );
439 assert_eq!(
440 aead.seal(&nonce13, &[0u8; 0xff00], &[0u8; 16]),
441 Err(crate::Error::InvalidInput)
442 );
443 assert_eq!(
444 tls.open(&nonce12, b"", &vec![0u8; 16 + (1 << 24)]),
445 Err(crate::Error::VerificationFailed)
446 );
447 }
448
449 #[test]
451 fn any_param_validation() {
452 let key = [0x11u8; 16];
453 for bad in [2usize, 18, 9, 5, 0] {
455 assert!(
456 matches!(
457 Aes128CcmAny::new(&key, bad),
458 Err(crate::Error::InvalidInput)
459 ),
460 "tag_len {bad} must be rejected"
461 );
462 }
463 for m in [4usize, 6, 8, 10, 12, 14, 16] {
465 assert!(Aes128CcmAny::new(&key, m).is_ok(), "tag_len {m}");
466 }
467
468 let any = Aes128CcmAny::new(&key, 8).unwrap();
469 for bad_nonce in [vec![0u8; 6], vec![0u8; 14]] {
471 assert_eq!(
472 any.seal(&bad_nonce, b"", b"pt"),
473 Err(crate::Error::InvalidInput),
474 "nonce len {} must be rejected",
475 bad_nonce.len()
476 );
477 assert_eq!(
478 any.open(&bad_nonce, b"", &[0u8; 24]),
479 Err(crate::Error::InvalidInput),
480 "nonce len {} must be rejected on open",
481 bad_nonce.len()
482 );
483 }
484 for n in 7usize..=13 {
486 let nonce = vec![0xa0u8; n];
487 let sealed = any.seal(&nonce, b"aad", b"payload").unwrap();
488 assert_eq!(sealed.len(), 7 + 8);
489 assert_eq!(any.open(&nonce, b"aad", &sealed).unwrap(), b"payload");
490 }
491 let nonce12 = [0u8; 12];
493 assert_eq!(
494 any.open(&nonce12, b"", &[0u8; 7]),
495 Err(crate::Error::VerificationFailed)
496 );
497 }
498}