use wasm_bindgen::prelude::*; use aes::Aes128Enc; use blowfish::Blowfish; use md5::{Md5, Digest}; use cipher::{ BlockEncrypt, BlockDecryptMut, KeyInit, KeyIvInit, block_padding::{NoPadding, ZeroPadding} }; type BfCbcDec = cbc::Decryptor; const TRACK_CDN_KEY: [u8; 16] = [106, 111, 54, 97, 101, 121, 54, 104, 97, 105, 100, 50, 84, 101, 105, 104]; const BF_SECRET: [u8; 16] = [103, 52, 101, 108, 53, 56, 119, 99, 48, 122, 118, 102, 57, 110, 97, 49]; #[wasm_bindgen] pub struct Cipher { cipher: BfCbcDec } #[wasm_bindgen] impl Cipher { #[wasm_bindgen(constructor)] pub fn new(id: &str) -> Self { let id_md5 = format!("{:x}", Md5::digest(id.as_bytes())); let id_md5 = id_md5.as_bytes(); let mut key = [0u8; 16]; for i in 0..16 { key[i] = id_md5[i] ^ id_md5[i+16] ^ BF_SECRET[i] }; Self { cipher: BfCbcDec::new_from_slices(&key, &[0, 1, 2, 3, 4, 5, 6, 7]).unwrap() } } pub fn decrypt_chunk(&self, chunk: &mut [u8]) { self.cipher.clone().decrypt_padded_mut::(chunk).unwrap(); } } #[wasm_bindgen] pub fn legacy_stream_url(md5_origin: &str, format: &str, id: &str, media_version: u8) -> String { // md5 origin + format num + id + media version let metadata = [ md5_origin.as_bytes(), &[b'\xa4'], format.as_bytes(), &[b'\xa4'], id.as_bytes(), &[b'\xa4'], media_version.to_string().as_bytes(), ].concat(); let hash = format!("{:x}", Md5::digest(&metadata)); // md5 hash + previous metadata let metadata_hash = [ hash.as_bytes(), &[b'\xa4'], &metadata, &[b'\xa4'], ].concat(); let cipher = Aes128Enc::new_from_slice(&TRACK_CDN_KEY).unwrap(); let ciphertext = cipher.encrypt_padded_vec::(&metadata_hash); format!("https://cdns-proxy-{}.dzcdn.net/mobile/1/{}", md5_origin.chars().next().unwrap(), hex::encode(ciphertext)) }