1use crate::{DeviceType, ManufacturerCode, SecurityMode};
2
3#[cfg(feature = "decryption")]
4use aes::Aes128;
5#[cfg(feature = "decryption")]
6use cbc::{
7 Decryptor,
8 cipher::{BlockDecryptMut, KeyIvInit},
9};
10
11#[derive(Debug, Clone, PartialEq)]
12pub struct KeyContext {
13 pub manufacturer: ManufacturerCode,
14 pub identification_number: u32,
15 pub version: u8,
16 pub device_type: DeviceType,
17 pub security_mode: SecurityMode,
18 pub access_number: u8,
19}
20
21#[derive(Debug, Clone, Copy, PartialEq)]
22pub enum DecryptionError {
23 UnsupportedMode(SecurityMode),
24 KeyNotFound,
25 DecryptionFailed,
26 InvalidKeyLength,
27 InvalidDataLength,
28 NotEncrypted,
29 UnknownEncryptionState,
30}
31
32impl core::fmt::Display for DecryptionError {
33 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34 match self {
35 Self::UnsupportedMode(mode) => write!(f, "Unsupported security mode: {:?}", mode),
36 Self::KeyNotFound => write!(f, "Decryption key not found"),
37 Self::DecryptionFailed => write!(f, "Decryption operation failed"),
38 Self::InvalidKeyLength => write!(f, "Invalid key length"),
39 Self::InvalidDataLength => write!(f, "Invalid data length"),
40 Self::NotEncrypted => write!(f, "Data is not encrypted"),
41 Self::UnknownEncryptionState => {
42 write!(f, "Unknown encryption state for this data block type")
43 }
44 }
45 }
46}
47
48impl core::error::Error for DecryptionError {}
49
50pub trait KeyProvider {
51 fn get_key(&self, context: &KeyContext) -> Result<&[u8], DecryptionError>;
52}
53
54#[derive(Debug)]
55pub struct EncryptedPayload<'a> {
56 pub data: &'a [u8],
57 pub context: KeyContext,
58}
59
60impl<'a> EncryptedPayload<'a> {
61 pub fn new(data: &'a [u8], context: KeyContext) -> Self {
62 Self { data, context }
63 }
64
65 #[cfg(feature = "decryption")]
66 pub fn decrypt_into<K: KeyProvider>(
67 &self,
68 provider: &K,
69 output: &mut [u8],
70 ) -> Result<usize, DecryptionError> {
71 let key = provider.get_key(&self.context)?;
72
73 match self.context.security_mode {
74 SecurityMode::NoEncryption => {
75 let len = self.data.len();
76 let dest = output
77 .get_mut(..len)
78 .ok_or(DecryptionError::InvalidDataLength)?;
79 dest.copy_from_slice(self.data);
80 Ok(len)
81 }
82 SecurityMode::AesCbc128IvZero => {
83 decrypt_aes_cbc_into(self.data, key, &[0u8; 16], output)
84 }
85 SecurityMode::AesCbc128IvNonZero => {
86 let iv = self._derive_iv();
87 decrypt_aes_cbc_into(self.data, key, &iv, output)
88 }
89 mode => Err(DecryptionError::UnsupportedMode(mode)),
90 }
91 }
92
93 #[cfg(feature = "decryption")]
94 fn _derive_iv(&self) -> [u8; 16] {
95 let mut iv = [0u8; 16];
96 let mfr_id = self.context.manufacturer.to_id();
98 iv[0..2].copy_from_slice(&mfr_id.to_le_bytes());
99 let bcd_bytes = decimal_to_bcd(self.context.identification_number);
101 iv[2..6].copy_from_slice(&bcd_bytes);
102 iv[6] = self.context.version;
104 iv[7] = self.context.device_type.into();
106 iv[8..16].fill(self.context.access_number);
108 iv
109 }
110}
111
112#[cfg(feature = "decryption")]
115fn decimal_to_bcd(mut value: u32) -> [u8; 4] {
116 let mut bcd = [0u8; 4];
117 for byte in &mut bcd {
118 let low = (value % 10) as u8;
119 value /= 10;
120 let high = (value % 10) as u8;
121 value /= 10;
122 *byte = (high << 4) | low;
123 }
124 bcd
125}
126
127pub struct StaticKeyProvider<const N: usize> {
128 entries: [(u64, [u8; 16]); N],
129 count: usize,
130}
131
132impl<const N: usize> Default for StaticKeyProvider<N> {
133 fn default() -> Self {
134 Self {
135 entries: [(0, [0u8; 16]); N],
136 count: 0,
137 }
138 }
139}
140
141impl<const N: usize> StaticKeyProvider<N> {
142 pub fn new() -> Self {
143 Self::default()
144 }
145
146 pub fn add_key(
147 &mut self,
148 manufacturer_id: u16,
149 identification_number: u32,
150 key: [u8; 16],
151 ) -> Result<(), DecryptionError> {
152 let key_id = Self::compute_key_id(manufacturer_id, identification_number);
153 let entry = self
154 .entries
155 .get_mut(self.count)
156 .ok_or(DecryptionError::InvalidDataLength)?;
157 *entry = (key_id, key);
158 self.count += 1;
159 Ok(())
160 }
161
162 const fn compute_key_id(manufacturer_id: u16, identification_number: u32) -> u64 {
163 ((manufacturer_id as u64) << 32) | (identification_number as u64)
164 }
165}
166
167impl<const N: usize> KeyProvider for StaticKeyProvider<N> {
168 fn get_key(&self, context: &KeyContext) -> Result<&[u8], DecryptionError> {
169 let manufacturer_id = context.manufacturer.to_id();
170
171 let key_id = Self::compute_key_id(manufacturer_id, context.identification_number);
172
173 self.entries[..self.count]
174 .iter()
175 .find(|(id, _)| *id == key_id)
176 .map(|(_, key)| key.as_slice())
177 .ok_or(DecryptionError::KeyNotFound)
178 }
179}
180
181#[cfg(feature = "decryption")]
182fn decrypt_aes_cbc_into(
183 data: &[u8],
184 key: &[u8],
185 iv: &[u8],
186 output: &mut [u8],
187) -> Result<usize, DecryptionError> {
188 if key.len() != 16 {
189 return Err(DecryptionError::InvalidKeyLength);
190 }
191
192 if iv.len() != 16 {
193 return Err(DecryptionError::InvalidDataLength);
194 }
195
196 if data.is_empty() {
197 return Err(DecryptionError::InvalidDataLength);
198 }
199
200 let len = data.len();
201 let encrypted_len = len - (len % 16);
203
204 if encrypted_len == 0 {
205 let dest = output
207 .get_mut(..len)
208 .ok_or(DecryptionError::InvalidDataLength)?;
209 dest.copy_from_slice(data);
210 return Ok(len);
211 }
212
213 let dest = output
215 .get_mut(..len)
216 .ok_or(DecryptionError::InvalidDataLength)?;
217 dest.copy_from_slice(data);
218
219 type Aes128CbcDec = Decryptor<Aes128>;
221
222 let key_array: [u8; 16] = key
223 .try_into()
224 .map_err(|_| DecryptionError::InvalidKeyLength)?;
225 let iv_array: [u8; 16] = iv
226 .try_into()
227 .map_err(|_| DecryptionError::InvalidDataLength)?;
228
229 let decryptor = Aes128CbcDec::new(&key_array.into(), &iv_array.into());
230
231 let decrypt_buf = output
233 .get_mut(..encrypted_len)
234 .ok_or(DecryptionError::InvalidDataLength)?;
235 decryptor
236 .decrypt_padded_mut::<cipher::block_padding::NoPadding>(decrypt_buf)
237 .map_err(|_| DecryptionError::DecryptionFailed)?;
238
239 Ok(len)
241}
242
243#[cfg(all(test, feature = "decryption"))]
244mod tests {
245 use super::*;
246
247 #[test]
248 fn test_decrypt_aes_cbc_basic() {
249 let key = [0u8; 16];
251 let iv = [0u8; 16];
252 let encrypted = [
253 0x66, 0xe9, 0x4b, 0xd4, 0xef, 0x8a, 0x2c, 0x3b, 0x88, 0x4c, 0xfa, 0x59, 0xca, 0x34,
254 0x2b, 0x2e,
255 ];
256 let mut output = [0u8; 16];
257
258 let result = decrypt_aes_cbc_into(&encrypted, &key, &iv, &mut output);
259 assert!(result.is_ok());
260 let len = result.unwrap();
261 assert_eq!(len, 16);
262 }
263
264 #[test]
265 fn test_key_provider_basic() {
266 let mut provider = StaticKeyProvider::<10>::new();
267
268 let key = [
270 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
271 0x0F, 0x10,
272 ];
273
274 let manufacturer_code = ManufacturerCode::from_id(0x0421).unwrap(); let identification_number = 12345678u32;
277
278 provider
280 .add_key(0x0421, identification_number, key)
281 .unwrap();
282
283 let context = KeyContext {
285 manufacturer: manufacturer_code,
286 identification_number,
287 version: 0x01,
288 device_type: DeviceType::WaterMeter,
289 security_mode: crate::SecurityMode::AesCbc128IvZero,
290 access_number: 0x00,
291 };
292
293 let retrieved_key = provider.get_key(&context).unwrap();
295 assert_eq!(retrieved_key, &key);
296 }
297
298 #[test]
299 fn test_derive_iv() {
300 let manufacturer_code = ManufacturerCode::from_id(0x1ee6).unwrap(); let context = KeyContext {
302 manufacturer: manufacturer_code,
303 identification_number: 12345678,
304 version: 0x42,
305 device_type: DeviceType::WaterMeter,
306 security_mode: crate::SecurityMode::AesCbc128IvNonZero,
307 access_number: 0x50,
308 };
309
310 let payload = EncryptedPayload { data: &[], context };
311
312 let iv = payload._derive_iv();
313
314 assert_eq!(iv[0], 0xe6);
316 assert_eq!(iv[1], 0x1e);
317
318 assert_eq!(&iv[2..6], &[0x78, 0x56, 0x34, 0x12]);
321
322 assert_eq!(iv[6], 0x42);
324
325 assert_eq!(iv[7], 0x07);
327
328 for &byte in iv.iter().skip(8) {
330 assert_eq!(byte, 0x50);
331 }
332 }
333
334 #[test]
335 fn test_mode5_decryption_real_frame() {
336 let key = [
342 0xF8, 0xB2, 0x4F, 0x12, 0xF9, 0xD1, 0x13, 0xF6, 0x80, 0xBE, 0xE7, 0x65, 0xFD, 0xE6,
343 0x7E, 0xC0,
344 ];
345
346 let encrypted = [
348 0x98, 0xA7, 0x8E, 0x0D, 0x71, 0xAA, 0x63, 0x58, 0xEE, 0xBD, 0x0B, 0x20, 0xBF, 0xDF,
349 0x99, 0xED, 0xA2, 0xD2, 0x2F, 0xA2, 0x53, 0x14, 0xF3, 0xF1, 0xB8, 0x44, 0x70, 0x89,
350 0x8E, 0x49, 0x53, 0x03, 0x92, 0x37, 0x70, 0xBA, 0x8D, 0xDA, 0x97, 0xC9, 0x64, 0xF0,
351 0xEA, 0x6C, 0xE2, 0x4F, 0x56, 0x50, 0xC0, 0xA6, 0xCD, 0xF3, 0xDE, 0x37, 0xDE, 0x33,
352 0xFB, 0xFB, 0xEB, 0xAC, 0xE4, 0x00, 0x9B, 0xB0, 0xD8, 0xEB, 0xA2, 0xCB, 0xE8, 0x04,
353 0x33, 0xFF, 0x13, 0x13, 0x28, 0x20, 0x60, 0x20, 0xB1, 0xBF,
354 ];
355
356 let expected = [
358 0x2F, 0x2F, 0x0C, 0x13, 0x29, 0x73, 0x06, 0x00, 0x02, 0x6C, 0x94, 0x21, 0x82, 0x04,
359 0x6C, 0x81, 0x21, 0x8C, 0x04, 0x13, 0x75, 0x44, 0x06, 0x00, 0x8D, 0x04, 0x93, 0x13,
360 0x2C, 0xFB, 0xFE, 0x12, 0x44, 0x00, 0x51, 0x41, 0x00, 0x70, 0x35, 0x00, 0x77, 0x33,
361 0x00, 0x75, 0x49, 0x00, 0x16, 0x36, 0x00, 0x73, 0x56, 0x00, 0x91, 0x55, 0x00, 0x95,
362 0x57, 0x00, 0x31, 0x57, 0x00, 0x28, 0x42, 0x00, 0x18, 0x47, 0x00, 0x61, 0x39, 0x00,
363 0x56, 0x42, 0x00, 0x02, 0xFD, 0x17, 0x00, 0x00, 0x2F, 0x2F,
364 ];
365
366 let manufacturer = ManufacturerCode::from_id(0x6A49).unwrap();
370 let context = KeyContext {
371 manufacturer,
372 identification_number: 14639203, version: 0x00,
374 device_type: DeviceType::WaterMeter,
375 security_mode: crate::SecurityMode::AesCbc128IvNonZero,
376 access_number: 0x50,
377 };
378
379 let payload = EncryptedPayload {
381 data: &encrypted,
382 context: context.clone(),
383 };
384 let iv = payload._derive_iv();
385 let expected_iv = [
387 0x49, 0x6A, 0x03, 0x92, 0x63, 0x14, 0x00, 0x07, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50,
388 0x50, 0x50,
389 ];
390 assert_eq!(iv, expected_iv);
391
392 let mut provider = StaticKeyProvider::<1>::new();
394 provider.add_key(0x6A49, 14639203, key).unwrap();
395
396 let mut output = [0u8; 80];
397 let len = payload.decrypt_into(&provider, &mut output).unwrap();
398
399 assert_eq!(len, 80);
400 assert_eq!(&output[..80], &expected[..]);
401 }
402}