diff --git a/msg_tool_xp3data/crypt.json b/msg_tool_xp3data/crypt.json index 63d07a3..35f40ff 100644 --- a/msg_tool_xp3data/crypt.json +++ b/msg_tool_xp3data/crypt.json @@ -158,8 +158,14 @@ "PrologOrder": "AAEC", "OddBranchOrder": "BAMCBQAB", "EvenBranchOrder": "AAIHAwQBBgU=", - "Key": "Wa7phHMk/a0hEztfLDpfcWbN1n7e0DYitcdCV1m/2EQ=", - "Nonce": "DDEouJ4BezmeMVKZf7WVqA==", + "IndexKey1": { + "Key": "qITmTKxWdz7SPxrMP5zAJcLDiPpIBHzgCBCK5wtPUgw=", + "Nonce": "n+1KapDnHLI8hC3q3fxK/g==" + }, + "IndexKey2": { + "Key": "Wa7phHMk/a0hEztfLDpfcWbN1n7e0DYitcdCV1m/2EQ=", + "Nonce": "DDEouJ4BezmeMVKZf7WVqA==" + }, "FilterKey": 375708990042069900, "RandomType": 1, "ControlBlockName": "amb_after_ep1.bin", @@ -331,57 +337,15 @@ "PrologOrder": "AgAB", "OddBranchOrder": "BAEFAAMC", "EvenBranchOrder": "BgMBAgQFAAc=", - "FilterKey": 9413765695581088110, - "IndexKeyDict": { - "data.xp3": { - "Key": "sd8wA9myXvbA4ATJnq6JYia3V5otV84MkuSiW4aYOog=", - "Nonce": "HXJsNtEkHsOPDBcx/QODdQ==" - }, - "video.xp3": { - "Key": "sd8wA9myXvbA4ATJnq6JYia3V5otV84MkuSiW4aYOog=", - "Nonce": "HXJsNtEkHsOPDBcx/QODdQ==" - }, - "bgm.xp3": { - "Key": "sd8wA9myXvbA4ATJnq6JYia3V5otV84MkuSiW4aYOog=", - "Nonce": "HXJsNtEkHsOPDBcx/QODdQ==" - }, - "fgimage.xp3": { - "Key": "sd8wA9myXvbA4ATJnq6JYia3V5otV84MkuSiW4aYOog=", - "Nonce": "HXJsNtEkHsOPDBcx/QODdQ==" - }, - "bgimage.xp3": { - "Key": "sd8wA9myXvbA4ATJnq6JYia3V5otV84MkuSiW4aYOog=", - "Nonce": "HXJsNtEkHsOPDBcx/QODdQ==" - }, - "scn.xp3": { - "Key": "sd8wA9myXvbA4ATJnq6JYia3V5otV84MkuSiW4aYOog=", - "Nonce": "HXJsNtEkHsOPDBcx/QODdQ==" - }, - "voice.xp3": { - "Key": "sd8wA9myXvbA4ATJnq6JYia3V5otV84MkuSiW4aYOog=", - "Nonce": "HXJsNtEkHsOPDBcx/QODdQ==" - }, - "main.xp3": { - "Key": "sd8wA9myXvbA4ATJnq6JYia3V5otV84MkuSiW4aYOog=", - "Nonce": "HXJsNtEkHsOPDBcx/QODdQ==" - }, - "evimage.xp3": { - "Key": "sd8wA9myXvbA4ATJnq6JYia3V5otV84MkuSiW4aYOog=", - "Nonce": "HXJsNtEkHsOPDBcx/QODdQ==" - }, - "uipsd.xp3": { - "Key": "sd8wA9myXvbA4ATJnq6JYia3V5otV84MkuSiW4aYOog=", - "Nonce": "HXJsNtEkHsOPDBcx/QODdQ==" - }, - "video2.xp3": { - "Key": "9lU4Kgw+IvRM3Zm0ubsa161RAxURD9ghXmSvYH7f/VE=", - "Nonce": "r5eGhOPufNjqgZMwtggGhg==" - }, - "adult.xp3": { - "Key": "9lU4Kgw+IvRM3Zm0ubsa161RAxURD9ghXmSvYH7f/VE=", - "Nonce": "r5eGhOPufNjqgZMwtggGhg==" - } + "IndexKey1": { + "Key": "9lU4Kgw+IvRM3Zm0ubsa161RAxURD9ghXmSvYH7f/VE=", + "Nonce": "r5eGhOPufNjqgZMwtggGhg==" }, + "IndexKey2": { + "Key": "sd8wA9myXvbA4ATJnq6JYia3V5otV84MkuSiW4aYOog=", + "Nonce": "HXJsNtEkHsOPDBcx/QODdQ==" + }, + "FilterKey": 9413765695581088110, "ControlBlockName": "cafe_stella_steam.bin", "Title": "喫茶ステラと死神の蝶 [Steam] | 星光咖啡馆与死神之蝶 [Steam] | 星光咖啡館與死神之蝶 [Steam]" }, @@ -492,8 +456,14 @@ "PrologOrder": "AAIB", "OddBranchOrder": "AAEDBAUC", "EvenBranchOrder": "AAIEBwEDBQY=", - "Key": "4ozUw00nStHvknH8ECpqL1BVC9nOrpdryY4wHKtBTFE=", - "Nonce": "pjhv8KmiW/gnbdoy6c5J6Q==", + "IndexKey1": { + "Key": "2+qfpN7+FNCJA82aDwKn+Bl6W1lsp6ZRmDwtghduU5U=", + "Nonce": "28WWa+SxnONuANYPjybnWg==" + }, + "IndexKey2": { + "Key": "4ozUw00nStHvknH8ECpqL1BVC9nOrpdryY4wHKtBTFE=", + "Nonce": "pjhv8KmiW/gnbdoy6c5J6Q==" + }, "FilterKey": 12271333071625965214, "ControlBlockName": "dc5.bin", "Title": "D.C.5 ~ダ・カーポ5~ | 初音岛5 | D.C.5 Plus Happiness ~ダ・カーポ5~プラスハピネス | D.C.5 ~Da Capo 5~ Future Link | D.C.5 Future Link ~ダ・カーポ5~ フューチャーリンク | D.C.5 Sweet Happiness ~ダ・カーポ5~スイートハピネス" diff --git a/src/scripts/kirikiri/archive/xp3/crypt/cx.rs b/src/scripts/kirikiri/archive/xp3/crypt/cx.rs index 0d6b947..7e1bcf1 100644 --- a/src/scripts/kirikiri/archive/xp3/crypt/cx.rs +++ b/src/scripts/kirikiri/archive/xp3/crypt/cx.rs @@ -2030,8 +2030,8 @@ impl std::fmt::Debug for CxdecDb { #[derive(Debug)] pub struct HxCrypt { base: CxEncryption, - key: [u8; 32], - nonce: [u8; 16], + key1: IndexKey, + key2: IndexKey, filter_key: u64, file_mapping: HashMap, path_mapping: HashMap, @@ -2089,28 +2089,19 @@ impl HxCrypt { pub fn new( base: BaseSchema, cx: &CxSchema, - index_key: Option<&IndexKey>, + index_key1: &IndexKey, + index_key2: &IndexKey, filter_key: u64, random_type: i32, file_list_name: Option<&str>, file_list_path: Option<&str>, - index_key_dict: &HashMap, filename: &str, ) -> Result { - let mut index_key = if let Some(fkey) = index_key { - Some(fkey.clone()) - } else { - None - }; let p = std::path::Path::new(filename); let b = p .file_name() .ok_or_else(|| anyhow::anyhow!("Failed to get file name from path."))?; let s: &str = &b.to_string_lossy(); - if let Some(ind) = index_key_dict.get(s) { - index_key = Some(ind.clone()) - } - let index_key = index_key.ok_or_else(|| anyhow::anyhow!("Can not find index key."))?; let (file_map, mut path_map) = if let Some(path) = file_list_path { let data = std::fs::read(path)?; let data = decode_to_string(Encoding::Utf8, &data, true)?; @@ -2139,8 +2130,8 @@ impl HxCrypt { filename, Box::new(HxProgramBuilder::new(random_type)), )?, - key: index_key.key, - nonce: index_key.nonce, + key1: index_key1.clone(), + key2: index_key2.clone(), filter_key, file_mapping: file_map, path_mapping: path_map, @@ -2225,19 +2216,24 @@ impl HxCrypt { Ok((file_map, path_map)) } - fn create_chacha20_crypt(&self) -> Result { + fn create_chacha20_crypt(&self, flags: u16) -> Result { use chacha20::{KeyIvInit, cipher::StreamCipherSeek}; + let key = match flags { + 0 => &self.key2, + 1 => &self.key1, + _ => anyhow::bail!("Unknown hxv4 flags: {}", flags), + }; let mut nonce = [0; 8]; - nonce.copy_from_slice(&self.nonce[..8]); - let mut crypt = ChaCha20Legacy::new((&self.key).into(), (&nonce).into()); + nonce.copy_from_slice(&key.nonce[..8]); + let mut crypt = ChaCha20Legacy::new((&key.key).into(), (&nonce).into()); crypt.try_seek(64)?; Ok(crypt) } - fn read_index(&self, mut stream: T) -> Result<()> { + fn read_index(&self, mut stream: T, flags: u16) -> Result<()> { use chacha20::cipher::StreamCipher; let len = stream.stream_length()?; - let mut crypt = self.create_chacha20_crypt()?; + let mut crypt = self.create_chacha20_crypt(flags)?; let tlen = len as usize - 16; let mut buf = Vec::with_capacity(tlen); stream.seek(SeekFrom::Start(16))?; @@ -2388,12 +2384,12 @@ impl Crypt for HxCrypt { let mut reader = MemReaderRef::new(&hxv4.data); let offset = reader.read_u64()? + archive.base_offset; let size = reader.read_u32()?; - let _flags = reader.read_u16()?; + let flags = reader.read_u16()?; let stream = StreamRegion::with_size( MutexWrapper::new(archive.inner.clone(), offset), size as u64, )?; - self.read_index(stream)?; + self.read_index(stream, flags)?; let info_map = self.info_map.lock_blocking(); for entry in archive.entries.iter_mut() { if let Some(info) = info_map.get(&entry.name) { diff --git a/src/scripts/kirikiri/archive/xp3/crypt/mod.rs b/src/scripts/kirikiri/archive/xp3/crypt/mod.rs index dfc2712..71bae32 100644 --- a/src/scripts/kirikiri/archive/xp3/crypt/mod.rs +++ b/src/scripts/kirikiri/archive/xp3/crypt/mod.rs @@ -288,15 +288,13 @@ enum CryptType { HxCrypt { #[serde(flatten)] cx: CxSchema, - #[serde(default, flatten)] - index_key: Option, + index_key1: cx::IndexKey, + index_key2: cx::IndexKey, filter_key: u64, #[serde(default)] random_type: i32, #[serde(default)] file_list_name: Option, - #[serde(default)] - index_key_dict: HashMap, }, } @@ -490,20 +488,20 @@ impl Schema { )?), CryptType::HxCrypt { cx, - index_key, + index_key1, + index_key2, filter_key, random_type, file_list_name, - index_key_dict, } => Box::new(cx::HxCrypt::new( self.base.clone(), cx, - index_key.as_ref(), + index_key1, + index_key2, *filter_key, *random_type, file_list_name.as_ref().map(|s| s.as_str()), config.xp3_file_list_path.as_ref().map(|s| s.as_str()), - index_key_dict, filename, )?), })