From ca24c31edef78afd67a711524b5729a8e3001cc0 Mon Sep 17 00:00:00 2001 From: lifegpc Date: Fri, 10 Apr 2026 15:29:05 +0800 Subject: [PATCH] Add YuzuCrypt --- msg_tool_xp3data/crypt.json | 6 ++- src/scripts/kirikiri/archive/xp3/crypt/mod.rs | 40 +++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/msg_tool_xp3data/crypt.json b/msg_tool_xp3data/crypt.json index dec461a..3b5256b 100644 --- a/msg_tool_xp3data/crypt.json +++ b/msg_tool_xp3data/crypt.json @@ -1798,7 +1798,7 @@ "OddBranchOrder": "AgMEBQAB", "EvenBranchOrder": "BwYEAQMAAgU=", "ControlBlockName": "sabbat.bin", - "Title": "サノバウィッチ | 魔女的夜宴" + "Title": "サノバウィッチ [English] | 魔女的夜宴 [English]" }, "Saikyou Chikan Densha": { "$type": "FlyingShineCrypt", @@ -1818,6 +1818,10 @@ "Key": 209, "Title": "サメと生きる七日間 体験版" }, + "Sanoba Witch": { + "$type": "YuzuCrypt", + "Title": "サノバウィッチ | 魔女的夜宴" + }, "Sakura Sakura": { "$type": "HashCrypt", "Title": "さくらさくら" diff --git a/src/scripts/kirikiri/archive/xp3/crypt/mod.rs b/src/scripts/kirikiri/archive/xp3/crypt/mod.rs index 7417305..c3ffc26 100644 --- a/src/scripts/kirikiri/archive/xp3/crypt/mod.rs +++ b/src/scripts/kirikiri/archive/xp3/crypt/mod.rs @@ -187,6 +187,7 @@ enum CryptType { first_xor: u8, zero_xor: u8, }, + YuzuCrypt, } #[derive(Clone, Debug, Deserialize)] @@ -299,6 +300,7 @@ impl Schema { *first_xor, *zero_xor, )), + CryptType::YuzuCrypt => Box::new(YuzuCrypt::new(self.base.clone())), }) } } @@ -1304,6 +1306,24 @@ impl Read for SmileCryptReader { } } +seek_crypt_filehash_key_impl!(YuzuCrypt, YuzuCryptReader); + +impl Read for YuzuCryptReader { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + let readed = self.inner.read(buf)?; + let hash = self.key ^ 0x1DDB6E7A; + let mut key = (hash ^ (hash >> 8) ^ (hash >> 16) ^ (hash >> 24)) as u8; + if key == 0 { + key = 0xD0; + } + for t in (&mut buf[..readed]).iter_mut() { + *t ^= key; + } + self.pos += readed as u64; + Ok(readed) + } +} + #[test] fn test_deserialize_crypt() { for (key, schema) in CRYPT_SCHEMA.iter() { @@ -1311,6 +1331,26 @@ fn test_deserialize_crypt() { } } +#[test] +fn check_alias_exists() { + let mut alias = std::collections::HashSet::new(); + for (key, schema) in CRYPT_SCHEMA.iter() { + if alias.contains(key.as_str()) { + panic!("Game {} is already used", key); + } + alias.insert(key.to_string()); + if let Some(title) = &schema.title { + for part in title.split("|") { + let part = part.trim(); + if alias.contains(part) { + panic!("Game alias {} in {} is already used", part, key); + } + alias.insert(part.to_string()); + } + } + } +} + #[test] fn test_cx_cb_table() { for (key, list) in CX_CB_TABLE.iter() {