Add PoringSoftCrypt (tested game: https://vndb.org/v532 )

Add force decrypt option
This commit is contained in:
2026-04-09 13:47:20 +08:00
parent c81689961c
commit d1b1b162df
6 changed files with 85 additions and 1 deletions

View File

@@ -135,6 +135,10 @@
"$type": "HashCrypt",
"Title": "姉撮 ~堕ちていくお姉ちゃんを助けられない僕~"
},
"Aniki No Yome-san nara": {
"$type": "PoringSoftCrypt",
"Title": "兄貴の嫁さんなら、俺にハメられてヒイヒイ言ってるところだよ"
},
"Aqua": {
"$type": "CxEncryption",
"Mask": 424,
@@ -191,6 +195,10 @@
"$type": "HashCrypt",
"Title": "ビッチギャルのガチイキアクメ ~家庭教師の童貞巨根にハマり堕ち~ | Bitch Gyaru no Gachi Iki Acme"
},
"blue note": {
"$type": "PoringSoftCrypt",
"Title": "ブルーノート"
},
"Bodatsu ~Kindan no Shokushu Soukan~": {
"$type": "HashCrypt",
"Title": "母奪~禁断の触手相姦~"
@@ -205,6 +213,10 @@
"Key": 49,
"Title": "僕の未来は、恋と課金と。~Charge To The Future~ [体験版] | 我的未来是恋爱与氪金 [试用版]"
},
"Bra-ban!": {
"$type": "PoringSoftCrypt",
"Title": "ぶらばん! | 管乐恋曲!"
},
"Café Stella to Shinigami no Chou": {
"$type": "RiddleCxCrypt",
"Mask": 622,
@@ -743,6 +755,10 @@
"$type": "NatsupochiCrypt",
"Title": "妹孕ませっくす"
},
"Imouto Kairaku Ochi": {
"$type": "PoringSoftCrypt",
"Title": "妹快楽堕ち~お兄ちゃんに無理やりハメられてから~ | 沉溺快感中的妹妹~自从被哥哥强行插入后~"
},
"Imouto Shokushu Rape": {
"$type": "HashCrypt",
"Title": "妹触手レイプ ~復讐の処女貫通~"
@@ -1084,6 +1100,10 @@
"$type": "DieselmineCrypt",
"Title": "M-days 慟哭の交尾地獄"
},
"Mahara Miko": {
"$type": "PoringSoftCrypt",
"Title": "魔孕巫女~お清めは愛欲淫靡に~"
},
"Mahoutsukai no Yoru": {
"$type": "CxEncryption",
"Mask": 554,
@@ -1214,6 +1234,10 @@
"$type": "HashCrypt",
"Title": "桃尻インストラクター寝取りレッスン ~競泳水着でえろざんまい~"
},
"Muchimuchi Dekapai Mara Gui Maou-sama": {
"$type": "PoringSoftCrypt",
"Title": "ムチムチデカパイマラ喰い魔王様とおんぼろ四畳半同棲生活 | 与爆乳魔王的同居生活"
},
"Mugen no Tír na nÓg": {
"$type": "XorCrypt",
"Key": 85,
@@ -1227,6 +1251,10 @@
"$type": "HashCrypt",
"Title": "軟体レッスン ~いいなり彼女とひみつの放課後~"
},
"Nariyuki→Papakatsu Girls!!": {
"$type": "PoringSoftCrypt",
"Title": "なりゆき→パパ活GIRLS!! | 惠里和千寻的援交日记"
},
"Natsu no Owari": {
"$type": "XorCrypt",
"Key": 87,
@@ -1236,6 +1264,10 @@
"$type": "NatsupochiCrypt",
"Title": "夏色姉妹 ~幼馴染と真夏のヒメゴト~ | 夏色姐妹~青梅竹马与盛夏秘事~"
},
"Natsuiro Shimai Trial": {
"$type": "PoringSoftCrypt",
"Title": "夏色姉妹 ~幼馴染と真夏のヒメゴト~ 体験版"
},
"Natsupochi": {
"$type": "NatsupochiCrypt",
"Title": "なつぽち"
@@ -1311,6 +1343,10 @@
"$type": "OkibaCrypt",
"Title": "置き場がない!"
},
"Oku-sama wa Moto Yariman -Besluted-": {
"$type": "PoringSoftCrypt",
"Title": "奥様は元ヤリマン ―Besluted―"
},
"Omae no Kaa-chan, Ii Onna Da yo na": {
"$type": "NatsupochiCrypt",
"Title": "お前の母ちゃん、良い女だよな。 | 你妈真漂亮 | 你媽真漂亮"
@@ -1471,6 +1507,9 @@
"EvenBranchOrder": "BAYBBQIHAAM=",
"ControlBlockName": "pendulum.bin"
},
"PRICE": {
"$type": "PoringSoftCrypt"
},
"Princess Saga": {
"$type": "FlyingShineCrypt",
"Title": "プリンセスサーガ"
@@ -1546,6 +1585,10 @@
"EvenBranchOrder": "BgQFAAIHAQM=",
"ControlBlockName": "riddle_steam.bin"
},
"Riding Incubus": {
"$type": "PoringSoftCrypt",
"Title": "らいでぃんぐ いんきゅばす"
},
"Rui wa Tomo o Yobu": {
"$type": "CxEncryption",
"Mask": 740,
@@ -1679,6 +1722,10 @@
"$type": "FlyingShineCrypt",
"Title": "親友の巨乳ママと中出し性活~こんなに射精してちゃ孕んじゃったね"
},
"Shindan no Kekka, Sore wa Koi no Yamai Desu": {
"$type": "PoringSoftCrypt",
"Title": "診断の結果、それは恋の病です | 诊断的结果、那是名为恋爱的病"
},
"Shiniyuku Kimi, Yakata ni Mebuku Zouo": {
"$type": "CxEncryption",
"Mask": 379,
@@ -1896,6 +1943,10 @@
"ControlBlockName": "towazugatari.bin",
"Title": "永遠ズ語リ~少女凌辱秘抄~"
},
"Tsubasa no Oka no Hime": {
"$type": "PoringSoftCrypt",
"Title": "つばさの丘の姫王 A red and blue moon -finite loop-"
},
"Tsuma Kai -Tsuma Gai-": {
"$type": "FlyingShineCrypt",
"Title": "貸し出し妻、満里奈の“ネトラセ”報告 外伝1 ―女子校生、満里奈の性感開発―"

View File

@@ -732,6 +732,11 @@ pub struct Arg {
#[arg(long, global = true)]
/// Force extract encrypted files in Kirikiri XP3 archive without decryption.
pub xp3_force_extract: bool,
#[cfg(feature = "kirikiri-arc")]
#[arg(long, global = true, visible_alias = "xp3-fd")]
/// Force decrypt files in Kirikiri xp3 archive even when flags are not set.
/// Some encrypted files in Kirikiri XP3 archive may not set encryption flag, but still encrypted. Enable this to force decrypt these files.
pub xp3_force_decrypt: bool,
#[command(subcommand)]
/// Command
pub command: Command,

View File

@@ -3397,6 +3397,8 @@ fn main() {
xp3_debug_archive: arg.xp3_debug_archive,
#[cfg(feature = "kirikiri-arc")]
xp3_force_extract: arg.xp3_force_extract,
#[cfg(feature = "kirikiri-arc")]
xp3_force_decrypt: arg.xp3_force_decrypt,
});
match &arg.command {
args::Command::Export { input, output } => {

View File

@@ -165,6 +165,7 @@ enum CryptType {
NephriteCrypt,
AlteredPinkCrypt,
NatsupochiCrypt,
PoringSoftCrypt,
}
#[derive(Clone, Debug, Deserialize)]
@@ -257,6 +258,7 @@ impl Schema {
CryptType::NephriteCrypt => Box::new(NephriteCrypt::new(self.base.clone())),
CryptType::AlteredPinkCrypt => Box::new(AlteredPinkCrypt::new(self.base.clone())),
CryptType::NatsupochiCrypt => Box::new(NatsupochiCrypt::new(self.base.clone())),
CryptType::PoringSoftCrypt => Box::new(PoringSoftCrypt::new(self.base.clone())),
})
}
}
@@ -910,6 +912,20 @@ impl<R: Read> Read for NatsupochiCryptReader<R> {
}
}
seek_crypt_filehash_key_impl!(PoringSoftCrypt, PoringSoftCryptReader<T>);
impl<R: Read> Read for PoringSoftCryptReader<R> {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
let readed = self.inner.read(buf)?;
let key = (!w!(self.key + 1)) 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() {

View File

@@ -163,6 +163,7 @@ pub struct Xp3Archive {
decrypt_simple_crypt: bool,
decompress_mdf: bool,
force_extract: bool,
force_decrypt: bool,
}
impl Xp3Archive {
@@ -189,6 +190,7 @@ impl Xp3Archive {
decrypt_simple_crypt: config.xp3_simple_crypt,
decompress_mdf: config.xp3_mdf_decompress,
force_extract: config.xp3_force_extract,
force_decrypt: config.xp3_force_decrypt,
})
}
}
@@ -240,6 +242,7 @@ impl Script for Xp3Archive {
self.archive.base_offset,
crypt,
skip_decrypt,
self.force_decrypt,
);
let mut header = [0u8; 16];
let header_len = entry.read(&mut header)?;
@@ -314,6 +317,7 @@ struct Entry {
entries_pos: Vec<u64>,
script_type: Option<ScriptType>,
skip_decrypt: bool,
force_decrypt: bool,
}
#[automatically_derived]
@@ -341,6 +345,7 @@ impl Entry {
base_offset: u64,
crypt: Arc<Box<dyn Crypt>>,
skip_decrypt: bool,
force_decrypt: bool,
) -> Self {
let mut pos = 0;
let entries_pos = index
@@ -363,6 +368,7 @@ impl Entry {
crypt,
crypt_stream: None,
skip_decrypt,
force_decrypt,
}
}
}
@@ -419,7 +425,7 @@ impl Read for Entry {
let seg_pos = self.entries_pos[seg_index];
let skip_pos = self.pos - seg_pos;
let read_size = seg.archived_size;
if !self.skip_decrypt && self.index.is_encrypted() {
if !self.skip_decrypt && (self.index.is_encrypted() || self.force_decrypt) {
if seg.is_compressed || !self.crypt.decrypt_seek_supported() {
let mut cache: Box<dyn Read> = if seg.is_compressed {
let mut inner =

View File

@@ -645,6 +645,10 @@ pub struct ExtraConfig {
#[cfg(feature = "kirikiri-arc")]
/// Force extract encrypted files in Kirikiri XP3 archive without decryption.
pub xp3_force_extract: bool,
#[cfg(feature = "kirikiri-arc")]
/// Force decrypt files in Kirikiri xp3 archive even when flags are not set.
/// Some encrypted files in Kirikiri XP3 archive may not set encryption flag, but still encrypted. Enable this to force decrypt these files.
pub xp3_force_decrypt: bool,
}
#[cfg(feature = "artemis")]