diff --git a/Cargo.toml b/Cargo.toml index 203fc94..9a920fc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,3 +18,4 @@ aes = "0.8" flate2 = "1.0" hashbrown = "0.13" thiserror = "1.0" +base64 = "0.21.0" diff --git a/examples/subcommands/list.rs b/examples/subcommands/list.rs index fac3d43..853824e 100644 --- a/examples/subcommands/list.rs +++ b/examples/subcommands/list.rs @@ -1,4 +1,4 @@ -pub fn list(path: String, key: String) -> Result<(), unpak::Error> { +pub fn list(path: String, key: Option) -> Result<(), unpak::Error> { for file in super::load_pak(path, key)?.files() { println!("{file}"); } diff --git a/examples/subcommands/mod.rs b/examples/subcommands/mod.rs index 92ed864..7aeb140 100644 --- a/examples/subcommands/mod.rs +++ b/examples/subcommands/mod.rs @@ -5,16 +5,27 @@ pub use {list::list, unpack::unpack, version::version}; fn load_pak( path: String, - key: String, + key: Option, ) -> Result>, unpak::Error> { + use aes::cipher::KeyInit; + use base64::{engine::general_purpose, Engine as _}; + let key = key + .map(|k| { + general_purpose::STANDARD + .decode(k) + .as_ref() + .map_err(|_| unpak::Error::Base64) + .and_then(|bytes| { + aes::Aes256Dec::new_from_slice(bytes).map_err(|_| unpak::Error::Aes) + }) + }) + .transpose()?; + for ver in unpak::Version::iter() { match unpak::Pak::new( std::io::BufReader::new(std::fs::OpenOptions::new().read(true).open(&path)?), ver, - match key.as_bytes() { - &[] => None, - key => Some(key), - }, + key.clone(), ) { Ok(pak) => { return Ok(pak); diff --git a/examples/subcommands/unpack.rs b/examples/subcommands/unpack.rs index f85f492..715f6e9 100644 --- a/examples/subcommands/unpack.rs +++ b/examples/subcommands/unpack.rs @@ -1,4 +1,4 @@ -pub fn unpack(path: String, key: String) -> Result<(), unpak::Error> { +pub fn unpack(path: String, key: Option) -> Result<(), unpak::Error> { let folder = std::path::Path::new( std::path::Path::new(&path) .file_stem() diff --git a/examples/subcommands/version.rs b/examples/subcommands/version.rs index 8cf1eac..9247d8b 100644 --- a/examples/subcommands/version.rs +++ b/examples/subcommands/version.rs @@ -1,4 +1,4 @@ -pub fn version(path: String, key: String) -> Result<(), unpak::Error> { +pub fn version(path: String, key: Option) -> Result<(), unpak::Error> { println!("{}", super::load_pak(path, key)?.version()); Ok(()) } diff --git a/examples/unpak.rs b/examples/unpak.rs index e9bc46c..6f09d70 100644 --- a/examples/unpak.rs +++ b/examples/unpak.rs @@ -8,9 +8,9 @@ fn main() { }; // can't map key to &[u8] because refers to owned data if let Err(e) = match args.next().unwrap_or_default().as_str() { - "version" => subcommands::version(path, args.next().unwrap_or_default()), - "list" => subcommands::list(path, args.next().unwrap_or_default()), - "unpack" | "" => subcommands::unpack(path, args.next().unwrap_or_default()), + "version" => subcommands::version(path, args.next()), + "list" => subcommands::list(path, args.next()), + "unpack" | "" => subcommands::unpack(path, args.next()), "help" | _ => help(), } { eprintln!("{e}") diff --git a/src/error.rs b/src/error.rs index 1ae8164..b09c80b 100644 --- a/src/error.rs +++ b/src/error.rs @@ -5,6 +5,8 @@ pub enum Error { Strum(#[from] strum::ParseError), #[error("key hash is an incorrect length")] Aes, + #[error("malformed base64")] + Base64, // std errors #[error("io error: {0}")] Io(#[from] std::io::Error), diff --git a/src/pak.rs b/src/pak.rs index b4d5096..dde1016 100644 --- a/src/pak.rs +++ b/src/pak.rs @@ -14,7 +14,7 @@ impl Pak { pub fn new( mut reader: R, version: super::Version, - key_hash: Option<&[u8]>, + key: Option, ) -> Result { use super::ext::ReadExt; use byteorder::{ReadBytesExt, LE}; @@ -24,20 +24,15 @@ impl Pak { // read index to get all the entry info reader.seek(io::SeekFrom::Start(footer.index_offset))?; let mut index = reader.read_len(footer.index_size as usize)?; - let mut key = None; // decrypt index if needed if footer.encrypted { - let Some(hash) = key_hash else { + let Some(key) = &key else { return Err(super::Error::Encrypted); }; - use aes::cipher::{BlockDecrypt, KeyInit}; - let Ok(decrypter)= aes::Aes256Dec::new_from_slice(hash) else { - return Err(super::Error::Aes) - }; + use aes::cipher::BlockDecrypt; for chunk in index.chunks_mut(16) { - decrypter.decrypt_block(aes::Block::from_mut_slice(chunk)) + key.decrypt_block(aes::Block::from_mut_slice(chunk)) } - key = Some(decrypter); } let mut index = io::Cursor::new(index); let mount_point = index.read_string()?;