From 42fa26fdd43aee28f3a2ac31134a36e426f6f9cd Mon Sep 17 00:00:00 2001 From: lifegpc Date: Fri, 1 May 2026 23:23:52 +0800 Subject: [PATCH] Add FestivalCrypt (untested) --- msg_tool_xp3data/crypt.json | 4 ++++ src/scripts/kirikiri/archive/xp3/crypt/mod.rs | 16 ++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/msg_tool_xp3data/crypt.json b/msg_tool_xp3data/crypt.json index c4a6c8b..c6be55b 100644 --- a/msg_tool_xp3data/crypt.json +++ b/msg_tool_xp3data/crypt.json @@ -1171,6 +1171,10 @@ "Key": 247, "Title": "ココロのカタチとイロとオト | 心之形心之色心之声" }, + "Kon Kon": { + "$type": "FestivalCrypt", + "Title": "魂々" + }, "Kore tte, Riajuu?": { "$type": "HashCrypt", "Title": "これって、リア充? ~黒ギャルが、ドーテーを教育するそうですよ~" diff --git a/src/scripts/kirikiri/archive/xp3/crypt/mod.rs b/src/scripts/kirikiri/archive/xp3/crypt/mod.rs index 005609e..6df397a 100644 --- a/src/scripts/kirikiri/archive/xp3/crypt/mod.rs +++ b/src/scripts/kirikiri/archive/xp3/crypt/mod.rs @@ -243,6 +243,7 @@ enum CryptType { mask: u32, key_seq: Base64Bytes, }, + FestivalCrypt, } #[derive(Clone, Debug, Deserialize)] @@ -379,6 +380,7 @@ impl Schema { CryptType::SmxCrypt { mask, key_seq } => { Box::new(SmxCrypt::new(self.base.clone(), *mask, &key_seq.bytes)?) } + CryptType::FestivalCrypt => Box::new(FestivalCrypt::new(self.base.clone())), }) } } @@ -1864,6 +1866,20 @@ impl Read for SmxCryptReader { } } +seek_crypt_filehash_key_impl!(FestivalCrypt, FestivalCryptReader); + +impl Read for FestivalCryptReader { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + let readed = self.inner.read(buf)?; + let key = (!(self.key >> 7)) as u8; + 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() {