1#![forbid(unsafe_code)]
9
10use crate::Error;
11use aes::Aes128;
12use aes::cipher::{BlockCipherEncrypt, KeyInit};
13
14type Block16 = aes::cipher::Block<Aes128>;
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
18#[non_exhaustive]
19pub enum Scheme {
20 Cenc,
22}
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
29pub struct Pattern {
30 pub crypt_blocks: u8,
32 pub skip_blocks: u8,
34}
35
36impl Pattern {
37 pub const NONE: Self = Self {
39 crypt_blocks: 0,
40 skip_blocks: 0,
41 };
42
43 #[must_use]
45 pub const fn is_none(self) -> bool {
46 self.crypt_blocks == 0
47 }
48}
49
50#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
52pub struct Subsample {
53 pub clear_bytes: u16,
55 pub protected_bytes: u32,
57}
58
59pub fn decrypt_cenc(
66 key: &[u8; 16],
67 iv: &[u8; 16],
68 pattern: Pattern,
69 data: &mut [u8],
70 subsamples: &[Subsample],
71) -> Result<(), Error> {
72 apply_cenc(key, iv, pattern, data, subsamples)
73}
74
75pub fn encrypt_cenc(
77 key: &[u8; 16],
78 iv: &[u8; 16],
79 pattern: Pattern,
80 data: &mut [u8],
81 subsamples: &[Subsample],
82) -> Result<(), Error> {
83 apply_cenc(key, iv, pattern, data, subsamples)
84}
85
86fn apply_cenc(
87 key: &[u8; 16],
88 iv: &[u8; 16],
89 pattern: Pattern,
90 data: &mut [u8],
91 subsamples: &[Subsample],
92) -> Result<(), Error> {
93 if !pattern.is_none() {
94 return Err(Error::InvalidPattern);
96 }
97 let cipher = Aes128::new(&(*key).into());
98 let mut counter = *iv;
99 if subsamples.is_empty() {
100 xor_ctr(&cipher, &mut counter, data);
101 return Ok(());
102 }
103 let mut pos = 0usize;
104 for sub in subsamples {
105 let clear = usize::from(sub.clear_bytes);
106 let protected = sub.protected_bytes as usize;
107 let end_clear = pos.checked_add(clear).ok_or(Error::SubsampleOverflow)?;
108 let end_prot = end_clear
109 .checked_add(protected)
110 .ok_or(Error::SubsampleOverflow)?;
111 if end_prot > data.len() {
112 return Err(Error::SubsampleOverflow);
113 }
114 pos = end_clear;
116 if protected > 0 {
117 xor_ctr(&cipher, &mut counter, &mut data[pos..end_prot]);
118 }
119 pos = end_prot;
120 }
121 Ok(())
122}
123
124fn xor_ctr(cipher: &Aes128, counter: &mut [u8; 16], data: &mut [u8]) {
125 let mut offset = 0;
126 while offset < data.len() {
127 let mut block: Block16 = (*counter).into();
128 cipher.encrypt_block(&mut block);
129 let n = (data.len() - offset).min(16);
130 for i in 0..n {
131 data[offset + i] ^= block[i];
132 }
133 offset += n;
134 inc_be128(counter);
135 }
136}
137
138fn inc_be128(block: &mut [u8; 16]) {
140 for i in (0..16).rev() {
141 let (v, overflow) = block[i].overflowing_add(1);
142 block[i] = v;
143 if !overflow {
144 break;
145 }
146 }
147}
148
149#[must_use]
151pub fn iv_from_8(iv8: &[u8; 8]) -> [u8; 16] {
152 let mut out = [0u8; 16];
153 out[..8].copy_from_slice(iv8);
154 out
155}
156
157pub fn iv_from_constant(constant_iv: &[u8]) -> Result<[u8; 16], Error> {
159 match constant_iv.len() {
160 8 => {
161 let mut a = [0u8; 8];
162 a.copy_from_slice(constant_iv);
163 Ok(iv_from_8(&a))
164 }
165 16 => {
166 let mut a = [0u8; 16];
167 a.copy_from_slice(constant_iv);
168 Ok(a)
169 }
170 _ => Err(Error::InvalidKeyMaterial),
171 }
172}
173
174#[cfg(test)]
175#[path = "cenc_tests.rs"]
176mod tests;