Add XorCrypt (tested game: https://vndb.org/v23388 )

This commit is contained in:
2026-04-06 15:57:14 +08:00
parent 01216d49b1
commit 025b802fc9
2 changed files with 84 additions and 0 deletions

View File

@@ -35,6 +35,16 @@
"$type": "HashCrypt",
"Title": "母奪~禁断の触手相姦~"
},
"Boku no Mirai wa, Koi to Kakin to": {
"$type": "XorCrypt",
"Key": 227,
"Title": "僕の未来は、恋と課金と。~Charge To The Future~ | 我的未来是恋爱与氪金"
},
"Boku no Mirai wa, Koi to Kakin to [Trial]": {
"$type": "XorCrypt",
"Key": 49,
"Title": "僕の未来は、恋と課金と。~Charge To The Future~ [体験版] | 我的未来是恋爱与氪金 [试用版]"
},
"Custom Reido 4/4+/V": {
"$type": "HashCrypt",
"Title": "カスタム隷奴 4/4+/V"
@@ -43,6 +53,11 @@
"$type": "HashCrypt",
"Title": "誰もが彼女を狙ってる。 | 众人觊觎的女友"
},
"Deatte 5-fun wa Ore no Mono!": {
"$type": "XorCrypt",
"Key": 53,
"Title": "出会って5分は俺のもの! 時間停止と不可避な運命 | 5分钟的邂逅!时间停止与不可避免的命运 | 相见5分属于我!时间停止不可避的命运"
},
"Do-M Imouto O-nedari Kojin Lesson": {
"$type": "HashCrypt",
"Title": "ドM妹おねだり個人レッスン~私のSEX家庭教師お兄ちゃん~ | 义妹私教辅导~哥哥我是家庭教师"
@@ -170,6 +185,11 @@
"$type": "HashCrypt",
"Title": "カホゴな寮母の射精管理 ~ちゃんと我慢してくださいね?~"
},
"Kamidanomi Shisugite Ore no Mirai ga Yabai.": {
"$type": "XorCrypt",
"Key": 205,
"Title": "神頼みしすぎて俺の未来がヤバい。 | 求神太多我的未来糟糕了 | 太依赖咒术的我未来堪忧。"
},
"Kanpeki Seitokaichou no Himitsu no Seiheki": {
"$type": "HashCrypt",
"Title": "完璧生徒会長の秘密の性癖 ~高嶺の花の彼女をM女に開花させてやる~"
@@ -413,6 +433,16 @@
"$type": "HashCrypt",
"Title": "嫁探しが捗りすぎてヤバい。 | 新娘太好找了我很方!"
},
"Yurameku Kokoro ni Michita Sekai de": {
"$type": "XorCrypt",
"Key": 205,
"Title": "ゆらめく心に満ちた世界で、君の夢と欲望は叶うか | 三千心世界,梦终将实现"
},
"Yuusha to Maou to, Majo no Cafe": {
"$type": "XorCrypt",
"Key": 205,
"Title": "勇者と魔王と、魔女のカフェ"
},
"Zettai Sakusei! Succubus-chan": {
"$type": "HashCrypt",
"Title": "絶対搾精! サキュバスちゃん"

View File

@@ -64,6 +64,10 @@ enum CryptType {
FateCrypt,
MizukakeCrypt,
HashCrypt,
#[serde(rename_all = "PascalCase")]
XorCrypt {
key: u8,
},
}
#[derive(Clone, Debug, Deserialize)]
@@ -81,6 +85,7 @@ impl Schema {
CryptType::FateCrypt => Box::new(FateCrypt::new()),
CryptType::MizukakeCrypt => Box::new(MizukakeCrypt::new()),
CryptType::HashCrypt => Box::new(HashCrypt::new()),
CryptType::XorCrypt { key } => Box::new(XorCrypt::new(key)),
}
}
}
@@ -358,6 +363,55 @@ impl<R: Read> Read for HashCryptReader<R> {
}
}
#[derive(Debug)]
pub struct XorCrypt {
key: u8,
}
impl XorCrypt {
pub fn new(key: u8) -> Self {
Self { key }
}
}
impl Crypt for XorCrypt {
fn decrypt_supported(&self) -> bool {
true
}
fn decrypt_seek_supported(&self) -> bool {
true
}
fn decrypt<'a>(
&self,
_entry: &Xp3Entry,
cur_seg: &Segment,
stream: Box<dyn Read + 'a>,
) -> Result<Box<dyn ReadDebug + 'a>> {
Ok(Box::new(XorCryptReader::new(stream, cur_seg, self.key)))
}
fn decrypt_with_seek<'a>(
&self,
_entry: &Xp3Entry,
cur_seg: &Segment,
stream: Box<dyn ReadSeek + 'a>,
) -> Result<Box<dyn ReadSeek + 'a>> {
Ok(Box::new(XorCryptReader::new(stream, cur_seg, self.key)))
}
}
seek_reader_key_impl!(XorCryptReader<T>, u8);
impl<R: Read> Read for XorCryptReader<R> {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
let readed = self.inner.read(buf)?;
for t in (&mut buf[..readed]).iter_mut() {
*t ^= self.key;
}
self.pos += readed as u64;
Ok(readed)
}
}
#[test]
fn test_deserialize_crypt() {
for (key, schema) in CRYPT_SCHEMA.iter() {