1use crate::block::BlockCipher;
17use crate::key::ControlWord;
18use crate::stream::StreamCipher;
19
20pub fn scramble(cw: &ControlWord, data: &mut [u8]) {
24 let len = data.len();
25 if len < 8 {
26 return;
27 }
28
29 let sch = cw.expand_block();
30 let cws = cw.expand_stream();
31 let bc = BlockCipher::new(sch);
32
33 let nblocks = len / 8;
34
35 bc.encrypt_block(&mut data[(nblocks - 1) * 8..nblocks * 8]);
38
39 for i in (0..nblocks - 1).rev() {
41 for j in 0..8 {
42 data[i * 8 + j] ^= data[(i + 1) * 8 + j];
43 }
44 bc.encrypt_block(&mut data[i * 8..(i + 1) * 8]);
45 }
46
47 let iv: [u8; 8] = data[0..8].try_into().unwrap();
49 let mut sc = StreamCipher::new(&cws, &iv);
50 sc.xor_stream(&mut data[8..]);
51}
52
53pub fn descramble(cw: &ControlWord, data: &mut [u8]) {
57 let len = data.len();
58 if len < 8 {
59 return;
60 }
61
62 let sch = cw.expand_block();
63 let cws = cw.expand_stream();
64 let bc = BlockCipher::new(sch);
65
66 let iv: [u8; 8] = data[0..8].try_into().unwrap();
68 let mut sc = StreamCipher::new(&cws, &iv);
69 sc.xor_stream(&mut data[8..]);
70
71 let nblocks = len / 8;
73
74 bc.decrypt_block(&mut data[0..8]);
76
77 for i in 1..nblocks {
79 for j in 0..8 {
80 data[(i - 1) * 8 + j] ^= data[i * 8 + j];
81 }
82 bc.decrypt_block(&mut data[i * 8..(i + 1) * 8]);
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89
90 #[test]
91 fn short_payload_unchanged() {
92 let cw = ControlWord::from_bytes([0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]);
93 let mut data = [0xaa, 0xbb, 0xcc, 0xdd];
94 let orig = data;
95 scramble(&cw, &mut data);
96 assert_eq!(data, orig);
97 descramble(&cw, &mut data);
98 assert_eq!(data, orig);
99 }
100
101 #[test]
102 fn roundtrip() {
103 let cw = ControlWord::from_bytes([0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]);
104 let plaintext: [u8; 16] = [
106 0x00, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38, 0x40, 0x48, 0x50, 0x58, 0x60, 0x5b,
107 0x63, 0x6b,
108 ];
109 let mut data = plaintext;
110 scramble(&cw, &mut data);
111 assert_ne!(data, plaintext);
112 descramble(&cw, &mut data);
113 assert_eq!(data, plaintext);
114 }
115
116 #[test]
117 fn vector_13_16byte() {
118 let cw = ControlWord::from_bytes([0xf0, 0x70, 0x94, 0xf2, 0xca, 0x22, 0x74, 0x32]);
119 let plaintext: [u8; 16] = [
120 0x1e, 0x25, 0x49, 0x31, 0x30, 0x96, 0xf4, 0xe4, 0xc2, 0x79, 0x3c, 0x92, 0x54, 0x44,
121 0x66, 0x40,
122 ];
123 let expected: [u8; 16] = [
124 0x3d, 0xf6, 0x9d, 0xf1, 0x4e, 0x97, 0x82, 0x31, 0x1e, 0x31, 0xe6, 0x0f, 0xe0, 0x70,
125 0x17, 0x4e,
126 ];
127
128 let mut data = plaintext;
129 scramble(&cw, &mut data);
130 assert_eq!(data, expected, "Vector 13 scramble mismatch");
131
132 let mut data2 = expected;
133 descramble(&cw, &mut data2);
134 assert_eq!(data2, plaintext, "Vector 13 descramble mismatch");
135 }
136
137 #[test]
138 fn vector_15_64byte() {
139 let cw = ControlWord::from_bytes([0xc6, 0xe6, 0x2a, 0x81, 0xff, 0xd6, 0x18, 0xea]);
140 let plaintext: [u8; 64] = [
141 0x11, 0x80, 0xf1, 0x5b, 0x59, 0xf0, 0x0e, 0x95, 0x78, 0xd5, 0x74, 0x6a, 0x89, 0x10,
142 0x64, 0x2c, 0x1f, 0xfe, 0xc1, 0xd7, 0x01, 0x86, 0x26, 0xfe, 0xa5, 0xe1, 0xc3, 0x76,
143 0x6d, 0x2c, 0xfc, 0xc4, 0xa3, 0xaf, 0xc0, 0x47, 0x36, 0xeb, 0xa9, 0x24, 0x32, 0x66,
144 0xd8, 0xf6, 0x01, 0x35, 0x8e, 0x33, 0x63, 0x4e, 0x8b, 0x5c, 0x2e, 0x8b, 0x27, 0xec,
145 0xc7, 0x7d, 0x31, 0xfe, 0x5c, 0xf6, 0x8b, 0xbc,
146 ];
147 let expected: [u8; 64] = [
148 0x45, 0xd2, 0x49, 0x70, 0x85, 0x52, 0x6f, 0x02, 0x12, 0x94, 0x39, 0x41, 0x07, 0x2e,
149 0x59, 0x3a, 0x28, 0x93, 0x92, 0xf1, 0x99, 0x7e, 0x2c, 0x0e, 0x5d, 0x3d, 0x72, 0xd5,
150 0xe3, 0x9a, 0xc6, 0x70, 0x39, 0x81, 0x31, 0x43, 0x83, 0x2c, 0xd5, 0xc8, 0xf5, 0xd2,
151 0x7a, 0x28, 0x2b, 0xff, 0x5f, 0x4d, 0xb3, 0xc7, 0x2e, 0xce, 0xa8, 0xb1, 0xff, 0xbf,
152 0x7d, 0x12, 0x4d, 0x53, 0xe2, 0xa7, 0x91, 0x4b,
153 ];
154
155 let mut data = plaintext;
156 scramble(&cw, &mut data);
157 assert_eq!(data, expected, "Vector 15 scramble mismatch");
158
159 let mut data2 = expected;
160 descramble(&cw, &mut data2);
161 assert_eq!(data2, plaintext, "Vector 15 descramble mismatch");
162 }
163
164 #[test]
165 fn vector_14_32byte() {
166 let cw = ControlWord::from_bytes([0x1e, 0x27, 0x9a, 0xdd, 0xca, 0x1c, 0xf5, 0x32]);
168 let plaintext: [u8; 32] = [
169 0xf1, 0xb3, 0x6d, 0x88, 0x5c, 0x9b, 0x68, 0x16, 0xf7, 0xef, 0x1c, 0x31, 0x94, 0x46,
170 0xa5, 0x32, 0x66, 0x79, 0xe7, 0x26, 0x38, 0x32, 0x29, 0x39, 0x70, 0x39, 0x6e, 0xdf,
171 0xc7, 0x7e, 0x93, 0xc8,
172 ];
173 let expected: [u8; 32] = [
174 0xb9, 0x59, 0x3e, 0xbd, 0xe4, 0xae, 0x0a, 0x30, 0xc7, 0x57, 0xe8, 0x6f, 0xf7, 0x6e,
175 0x7a, 0x42, 0xb1, 0x17, 0x03, 0x16, 0xca, 0x69, 0x5d, 0x8b, 0x0f, 0x73, 0x7e, 0x1b,
176 0x62, 0x4e, 0x55, 0x54,
177 ];
178
179 let mut data = plaintext;
180 scramble(&cw, &mut data);
181 assert_eq!(data, expected, "Vector 14 scramble mismatch");
182
183 let mut data2 = expected;
184 descramble(&cw, &mut data2);
185 assert_eq!(data2, plaintext, "Vector 14 descramble mismatch");
186 }
187}