use crate::header::Header; use crate::{Decipher, KugouError}; pub struct DecipherV3 { slot_key: [u8; 16], file_key: [u8; 17], } impl DecipherV3 { fn hash_key>(data: T) -> [u8; 16] { let digest = umc_utils::md5(data); let mut result = [0u8; 16]; for (result, digest) in result.rchunks_exact_mut(2).zip(digest.chunks_exact(2)) { result[0] = digest[0]; result[1] = digest[1]; } result } pub fn new(header: &Header, slot_key: &[u8]) -> Result { let slot_key = Self::hash_key(slot_key); let mut file_key = [0x6b; 17]; file_key[..16].copy_from_slice(&Self::hash_key(header.file_key)); Ok(Self { slot_key, file_key }) } } impl Decipher for DecipherV3 { fn decrypt(&self, buffer: &mut [u8], offset: usize) { let slot_key_stream = self .slot_key .iter() .cycle() .skip(offset % self.slot_key.len()); let file_key_stream = self .file_key .iter() .cycle() .skip(offset % self.file_key.len()); let mut offset = offset as u32; let key_stream = slot_key_stream.zip(file_key_stream); for (datum, (&slot_key, &file_key)) in buffer.iter_mut().zip(key_stream) { let offset_key = offset.to_ne_bytes().iter().fold(0, |acc, &x| acc ^ x); let mut temp = *datum; temp ^= file_key; temp ^= temp.wrapping_shl(4); temp ^= slot_key; temp ^= offset_key; *datum = temp; offset = offset.wrapping_add(1); } } }