diff --git a/Cargo.toml b/Cargo.toml index e23c457..1c66ae9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,17 +1,19 @@ [package] name = "dlc-decrypter" version = "0.2.1" +edition = "2024" authors = ["Tobias Matt "] license = "MIT" repository = "https://github.com/Bubblepoint/dlc-decoder" description = "A decoder library for dlc files" [dependencies] -error-chain = "0.11.0" -base64 = "0.9.0" -reqwest = "0.8.5" +error-chain = "0.12.4" +base64 = "0.22.1" +reqwest = "0.13.0" rust-crypto = "0.2.36" regex = "1.0.0" +tokio = { version = "1", features = ["full"] } [lib] name = "dlc_decrypter" \ No newline at end of file diff --git a/examples/cli.rs b/examples/cli.rs index c004487..51c96ec 100644 --- a/examples/cli.rs +++ b/examples/cli.rs @@ -3,7 +3,8 @@ extern crate dlc_decrypter; use std::env; use dlc_decrypter::DlcDecoder; -fn main() { +#[tokio::main] +async fn main() { // Create the DlcDecoder let dd = DlcDecoder::new(); @@ -12,7 +13,7 @@ fn main() { // own name for arg in env::args().skip(1) { // hand over the file path - let dlc = dd.from_file(arg); + let dlc = dd.from_file(arg).await; // print the result println!("DLC: {:?}", dlc); diff --git a/src/lib.rs b/src/lib.rs index ac89259..1b70f95 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -62,10 +62,12 @@ use std::ops::Deref; use std::fs::File; use std::str; use reqwest::Client; -use reqwest::header::{Connection, UserAgent}; +use reqwest::header; use crypto::{buffer, aes, blockmodes }; use crypto::buffer::{ ReadBuffer, WriteBuffer }; use regex::Regex; +use base64::engine::general_purpose::STANDARD as BASE64; +use base64::Engine as _; @@ -146,20 +148,20 @@ impl DlcDecoder { } /// Decrypt a specified .dlc file - pub fn from_file>(&self, path: P) -> Result { + pub async fn from_file>(&self, path: P) -> Result { // read the file let mut file = File::open(path.into())?; let mut data = Vec::new(); file.read_to_end(&mut data)?; // return the decrypted dlc package - self.from_data(&data) + self.from_data(&data).await } /// Decrypt the contet of a .dlc file. - pub fn from_data(&self, data: &[u8]) -> Result { + pub async fn from_data(&self, data: &[u8]) -> Result { // decrypt the .dlc data - let data = self.decrypt_dlc(data)?; + let data = self.decrypt_dlc(data).await?; // parse the dlc header data let mut dlc = self.parse_header(&data)?; @@ -172,7 +174,7 @@ impl DlcDecoder { /******************* Private Functions *****************/ /// Decrypt the .dlc data to a plain String - fn decrypt_dlc(&self, data: &[u8]) -> Result { + async fn decrypt_dlc(&self, data: &[u8]) -> Result { // check if the file is to short to get the key out of it if data.len() <= 88 { bail!("Corrupted data"); @@ -182,17 +184,17 @@ impl DlcDecoder { let (data, key) = data.split_at(data.len() - 88); // get decrypten key - let key = self.get_jd_decryption_key(key)?; + let key = self.get_jd_decryption_key(key).await?; // decrypt the key let key = DlcDecoder::decrypt_raw_data(&key, &self.jd_decryption_key, &self.jd_decryption_iv)?; // decrypt the content - let data = base64::decode(data)?; + let data = BASE64.decode(data)?; let data = DlcDecoder::decrypt_raw_data(&data, key.deref(), key.deref())?; // format to text - let data = base64::decode(&data)?; + let data = BASE64.decode(&data)?; let data = String::from_utf8(data)?; return Ok(data); @@ -236,19 +238,17 @@ impl DlcDecoder { } /// Download the decryption key for the .dlc container - fn get_jd_decryption_key(&self, key: &[u8]) -> Result> { + async fn get_jd_decryption_key(&self, key: &[u8]) -> Result> { // build the request url let url = format!("http://service.jdownloader.org/dlcrypt/service.php?srcType=dlc&destType={}&data={}", &self.jd_app_name, str::from_utf8(key)?); // build up the request - let mut res = Client::new().get(&url) - .header(Connection::close()) - .header(UserAgent::new("Mozilla/5.3 (Windows; U; Windows NT 5.1; de; rv:1.8.1.6) Gecko/2232 Firefox/3.0.0.R")) - .send()?; + let res = Client::new().get(&url) + .header(header::CONNECTION, "close") + .header(header::USER_AGENT, "Mozilla/5.3 (Windows; U; Windows NT 5.1; de; rv:1.8.1.6) Gecko/2232 Firefox/3.0.0.R") + .send().await?; - // read the response - let mut key = Vec::new(); - res.read_to_end(&mut key)?; + let key = res.bytes().await?.to_vec(); // check if response is long enough if key.len() != 33 { @@ -256,7 +256,7 @@ impl DlcDecoder { }; // remove and - let key = base64::decode(&key[4..28])?; + let key = BASE64.decode(&key[4..28])?; Ok(key) } @@ -272,12 +272,12 @@ impl DlcDecoder { // extract the name let re = Regex::new(r#"name="([^"]*)"#)?; let t = re.find(&pck).ok_or("Can't find name in data")?; - dlc.name = String::from_utf8(base64::decode(&pck[t.start()+6..t.end()])?)?; + dlc.name = String::from_utf8(BASE64.decode(&pck[t.start()+6..t.end()])?)?; // extract the password - optional let re = Regex::new(r#"passwords="([^"]*)"#)?; if let Some(t) = re.find(&pck) { - dlc.password = String::from_utf8(base64::decode(&pck[t.start()+11..t.end()])?)?; + dlc.password = String::from_utf8(BASE64.decode(&pck[t.start()+11..t.end()])?)?; } Ok(dlc) @@ -315,7 +315,7 @@ impl DlcDecoder { /// Get the files details fn file_details(&self, data: String, pos: usize) -> String { // try to decode the data - let buf: String = match base64::decode(&data[pos..]) { + let buf: String = match BASE64.decode(&data[pos..]) { Ok(x) => { match String::from_utf8(x) { Ok(x) => x, @@ -345,22 +345,22 @@ fn aes_cbc_decryptor( key_size: KeySize, key: &[u8], iv: &[u8], - padding: X) -> Box { + padding: X) -> Box { match key_size { KeySize::KeySize128 => { let aes_dec = aessafe::AesSafe128Decryptor::new(key); let dec = Box::new(CbcDecryptor::new(aes_dec, padding, iv.to_vec())); - dec as Box + dec as Box } KeySize::KeySize192 => { let aes_dec = aessafe::AesSafe192Decryptor::new(key); let dec = Box::new(CbcDecryptor::new(aes_dec, padding, iv.to_vec())); - dec as Box + dec as Box } KeySize::KeySize256 => { let aes_dec = aessafe::AesSafe256Decryptor::new(key); let dec = Box::new(CbcDecryptor::new(aes_dec, padding, iv.to_vec())); - dec as Box + dec as Box } } } \ No newline at end of file