mirror of
https://github.com/lifegpc/msg-tool.git
synced 2026-07-08 01:31:53 +08:00
Add SenrenCxCrypt
This commit is contained in:
7
Cargo.lock
generated
7
Cargo.lock
generated
@@ -1345,6 +1345,12 @@ dependencies = [
|
|||||||
"xml5ever",
|
"xml5ever",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "md5"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ae960838283323069879657ca3de837e9f7bbb4c7bf6ea7f1b290d5e9476d2e0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.8.0"
|
version = "2.8.0"
|
||||||
@@ -1435,6 +1441,7 @@ dependencies = [
|
|||||||
"lz4",
|
"lz4",
|
||||||
"markup5ever",
|
"markup5ever",
|
||||||
"markup5ever_rcdom",
|
"markup5ever_rcdom",
|
||||||
|
"md5",
|
||||||
"memchr",
|
"memchr",
|
||||||
"mozjpeg",
|
"mozjpeg",
|
||||||
"msg-tool-jpegxl-sys",
|
"msg-tool-jpegxl-sys",
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ libtlg-rs = { version = "0.2", optional = true, features = ["encode"] }
|
|||||||
lz4 = { version = "1.28", optional = true }
|
lz4 = { version = "1.28", optional = true }
|
||||||
markup5ever = { version = "0.38", optional = true }
|
markup5ever = { version = "0.38", optional = true }
|
||||||
markup5ever_rcdom = { version = "0.38", optional = true }
|
markup5ever_rcdom = { version = "0.38", optional = true }
|
||||||
|
md5 = { version = "0.8", optional = true }
|
||||||
memchr = { version = "2.7", optional = true }
|
memchr = { version = "2.7", optional = true }
|
||||||
mozjpeg = { version = "0.10", optional = true }
|
mozjpeg = { version = "0.10", optional = true }
|
||||||
msg_tool_macro = { path = "./msg_tool_macro" }
|
msg_tool_macro = { path = "./msg_tool_macro" }
|
||||||
@@ -94,7 +95,7 @@ hexen-haus = ["memchr", "utils-str"]
|
|||||||
hexen-haus-arc = ["hexen-haus"]
|
hexen-haus-arc = ["hexen-haus"]
|
||||||
hexen-haus-img = ["hexen-haus", "image"]
|
hexen-haus-img = ["hexen-haus", "image"]
|
||||||
kirikiri = ["emote-psb", "fancy-regex", "flate2", "json", "lz4", "utils-escape"]
|
kirikiri = ["emote-psb", "fancy-regex", "flate2", "json", "lz4", "utils-escape"]
|
||||||
kirikiri-arc = ["kirikiri", "adler", "bytes", "fastcdc", "flate2", "int-enum", "msg_tool_xp3data", "parse-size", "sha2", "utils-serde-base64bytes", "utils-simple-pack", "zopfli", "zstd"]
|
kirikiri-arc = ["kirikiri", "adler", "bytes", "fastcdc", "flate2", "int-enum", "md5", "msg_tool_xp3data", "parse-size", "sha2", "utils-serde-base64bytes", "utils-simple-pack", "zopfli", "zstd"]
|
||||||
kirikiri-img = ["kirikiri", "image", "libtlg-rs"]
|
kirikiri-img = ["kirikiri", "image", "libtlg-rs"]
|
||||||
musica = []
|
musica = []
|
||||||
musica-arc = ["musica", "crc32fast", "flate2", "include-flate", "utils-blowfish", "utils-rc4", "utils-serde-base64bytes", "utils-xored-stream"]
|
musica-arc = ["musica", "crc32fast", "flate2", "include-flate", "utils-blowfish", "utils-rc4", "utils-serde-base64bytes", "utils-xored-stream"]
|
||||||
|
|||||||
@@ -1378,6 +1378,17 @@
|
|||||||
"$type": "HashCrypt",
|
"$type": "HashCrypt",
|
||||||
"Title": "閃電の守護騎士ニィナ"
|
"Title": "閃電の守護騎士ニィナ"
|
||||||
},
|
},
|
||||||
|
"Senren*Banka": {
|
||||||
|
"$type": "SenrenCxCrypt",
|
||||||
|
"Mask": 308,
|
||||||
|
"Offset": 1846,
|
||||||
|
"PrologOrder": "AQAC",
|
||||||
|
"OddBranchOrder": "AwECBAAF",
|
||||||
|
"EvenBranchOrder": "BwQDBgIAAQU=",
|
||||||
|
"NamesSectionId": "sen:",
|
||||||
|
"ControlBlockName": "senren_banka.bin",
|
||||||
|
"Title": "千恋*万花 | 千戀*萬花"
|
||||||
|
},
|
||||||
"Shikijou Kyoudan": {
|
"Shikijou Kyoudan": {
|
||||||
"$type": "HashCrypt",
|
"$type": "HashCrypt",
|
||||||
"Title": "色情教団 | 妃神会秘史"
|
"Title": "色情教団 | 妃神会秘史"
|
||||||
|
|||||||
15
msg_tool_xp3data/cx_cb/senren_banka.bin
Normal file
15
msg_tool_xp3data/cx_cb/senren_banka.bin
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
©%Wœ—±Zoï*ª£î�ôóò4@xà‘VEŠ‘©÷oö-€Ô—?õ²ŒŽ-^
›cL]2Ø7û„msŽ=Å@20}ŒÕ�Eaå{«˜ŒóœðqõdC(¨°Cù
Ñ¿Õj¤"›g¹\é.Á'ì³;ÃFÂLµZ™Ü½——æ_+ïIóu¼`û?Æ‘MŒ\ÙÜ‹ø¹æ¹o“[ÉÚ{e'Fƒ•W÷åô‡Q”nrì_?hŠÜi&°4</¸¤ó{DŠ”ù¦J.ã¿€ƒ’¼ùp¦«‡�H�Ámf�xs-!„òs£ô–r³Á;fËšþ'¤`ï‰ê"L"=ÅŒ³¿“Ÿtä䞣2Žq ^�_¿”´áê•zªmÒ¨—“`¾äL=Ĥf•&BÛLÉ)´ßÅФ¨Ü@,^Ômù:/û?^)p¼üº´Ú�²°6ÇÙù?aÕC«0n•�Kù°[ŽÍ‡:$ íÚo™Ânî›ý€³Ì„CÊýèF§€Ç´ë[Á¬\³OͪDQ>…öºH¶Ì=Rv.mùíÁYÿžDð‰Ü¥²Á¸µçŸFb>µf“Ó1X˜aÈc«;ÙSÁ„�€Aäø…‚…�ŸgŠá†Õ©T»ð¢ÏŒß18"°ö¬Ï#÷vàTê^æíüõ>�V«OÌgvÙ›/\*énÝ–gzuæeB=éI€³þdšBãÂI‰xÅÄfq…+Å„[’íÞêÄÝÖjwÛ
|
||||||
|
¼„;ùŽâÌ`\D�Ðø-é`(Æït=7ÅŽfF`©Ç?ãPÏ7IÓ%ÔÇî†
øxN¬ÍÊz\¹5èK¿OÈY•ïã¬h«âˆ…J�™Í‹S�bøZaAÙnê»Xp_ÝÌ‚(#ÑkQ¦æ¦bv·~_mìÈœew�'Þl‚×»?h\‹u4F]•¨N;;‡„؆G;··mq—vèÿ+N[ë>æEþ¨~NX|’ú×löeå(gÅ´N¸m\Ÿ¼Iù#n…
|
||||||
|
×°Ž�q}ŒLVÜHFë2Ê¿…æ•t�Qi!Ô·ôPñq MÆùyèÅ¢×^;ðr(GbIÒûëÄwR×#1I·h+bøÀÄôw_\€¼+J
iÖ.x²O!uq�H÷ݨI‘ª¬ÿ¨½cº^”oë ü¼G˜ûÂ[£�2‹&“5íÙ¦Úõø9½%NëÁßDäK&þE‡çþ¸×Ÿe§7L\�[î,ëŠ=¯WßóðK¥Z?iP&´6?²ýKjøÖJ¶ê=L§øÙû#d9ªýk º”¢÷¹â|å«Z¥ïˆÔp1¶ú/òÞw¢Tp›OŠÙ'ªÇþ%C¤PƒðÂLî:SSýòÛEpÙh�i®Ä$jİü'ÞÙYÇÿp.•€¯à÷hµ�¢ìfÂÑžßnp(Dÿ~/j2´Ì„™Ú‹§“c):‹]š$“w-9Óóä¼·“^Y
_yh.¹©Î:̦d“£;^£�Wô;^¸s"2›vXó$ü¨ïòdáÒåþX.”3¡ Ñè)½/ö”ëóîbæ°jÌPÞX›ÃqÏKoSŽY6»äŒ¸œ‰y�˜²'4Gb¬€f†»àL_YuÚV°ô9ZH¾£Gîÿ‰3ÀòGäbw ¾ÖvžX,
|
||||||
|
d
‡˜«xïekýÌbêE:ë-„s]Ç‹¦3Ë·W¼È‡Ûܦ¥,^™Ïe‚ut×v¾æf0-st>í÷îÛã»y—ÁgÅŒL�sgh±üï6�/è÷iЩŸñ
|
||||||
|
”r4‘"ÍÃòy%vSLõïÔAÊœ70ö„ªýÜf<\¦^‹õ?%ÃÖ‡¸°
ñ–Îõ,œûèÞ-ÂV"æâ° ¨‘ö~©ñ€EÍb#Ηé
£+Þa_ÊËrakki¯Ù½Áýa12´ÏFÔõ12KÎgâ•J†Æœ;žGu1øN±YL? ¬s®X�cƒ…'Ïaˆ‚ìX®>P��BË)¸ðdg�PBD*_9¥¶ú¡Ö³3;»Á2 ´”ÕÐ&Ÿ
÷
†W€ÎUØG0ƒô)_½G>‰L%£Dõ>qÚkÆÔ˜†©ÇÜÜ(\u&¤˜¹«rˆ6z¡°íÈÉ�|¬Ìé‰�&F ™ø{¨5ÃtnGo³Âž%ŸæÌgšX´Î—/‘‘‡0p¦ÉæÍ™¹z²bz ^pD�ÆÈ*Wš3óh„ø¶×\õ\28bìËÚ“x4/ÎÃZ¥«ùÚ�ÎÃ
ƒÁ¥W¨>�šâbu x‡-¢™Ì9ÀvÊaIq¹ŽrÍ´œ&�°fŒÖs@Fþ €ß®
ݨ?”™²´o{䮦Ò2“0³´–!\üxš¹
áçì¿~—;‹ŽÈ‰Æfn'õ»¾µ8áöäÕ.s½ÿzU¯ÂÃα(•b÷ðeù n¤ß{Á–)z!†‚±ÛñèhÔ¨|Ó�oþŸ¾M®à?ÿŠqbÞêznÕøÐÜ„-�©tº†HnPw¢4ü)_| 2(àcÞLYsaªjŶþ
|
||||||
|
U°ÉÅ)ø
|
||||||
|
=‡à[¥dÞtýäb¯¨Œ¼èRóÐ&†ßQÆVð3�òÏ/T*®˜ý ÜÔ7*ëܨ͟æ®ôð91À¥'öŠòŒMü�Ûœ¡¦ô>s�ÓˆÐY¯%
|
||||||
|
eä;I�cE–P,žŒg—°üÍÛ(ÝS2z›“†Õúáˆÿ¬*^<Ž1± v˜ëARÙ©“Þ5t8Äë|b�¨ù¥5{У1”ã76»Ùë
|
||||||
|
ñ.tåªÑÞ¾ëŒé^=AÐ1ŸiXEó^Ô-ñwîC˜EW�N@†Á�<’2pD`ŠÅjæµ§µ€3Ü€Š.ã.Ï,®Õ�1î1�åÛéÞÒ6&ØŸÀf6ý½„JY3@Ñ÷ïŠ-eÂë¹þGà™jGíâ@é@î_/¾’Z“Æ]q’£Œ}ÀÞ|o0âîgÃÓ•Òì˲: A 6áïÄŽ,ƒÎ‰g) à¬Ãn!¨ú,ÉQ{årþþ‰(ñØër7[e¦»Ï{²ÏŠ·&p¦5Œ\!�¼C©˜¡Õº xÝïrU!d`¨Ý-Bý„ÊlRð@ßnu Øé'-ÕÝæQd‡Š/”£;a}uü¼kïû-Ò½ªoa_jha&0¡QìîdÈ ß¤Q{–*’o‡åœÃON÷�¶�¼ûÔŠ]Üj×åù<‡¦Á’8Z‹×¶'�B+ß(JfÀÁï&z6þ
üU2Ãt�Ùå <aK^`sœÚ¨”©ÚûÃÈ¥ëY›>_ëÝp!E�»ÃUþ(¸ü�7vè·âssî÷’–Ço†aÓKßMeŠ£™^žŒ‚$È�[«Ðþ¤ÕtIY¬YAÝöò0p8ãZ°¦„µ^úO`¬~Ï*`‰”¢Séücmc8ñ¯æã“’âK}ªîË_
|
||||||
|
ëé°*�µeÖhn OÌ›õ¼gµv~,µà”¸¯&Å’�Ò-Ⱦ@ÏZþU•Óje2ŒôGØÊëZF]2ÍÓkº.Lõ 3ÎyÐXîïnezpì!:™½í·õÇv'˜“XéàfÉëežPû‹iå°¸\}ºÎÎ+‹ãoÇÚ
´°¿k‡)„ÔÞ7K÷±R<ñÁ!úûܬ}ÕÃ"ÉÁ³~ˆÌXÉù
©åI‹%_Oü;EÏÅ�ïAuu�ø%™t&º¨èÂø†ºÖ3úŽÜ9r÷*‚ªx…hJšGàƒVQâôæ Yñy5(ÃT쯔ÓA[FYæià¤Q…mŸ ŽJŒ¡æ¹î6¢/œ�Âå¬7CA²¡Juæg)W(_–>¨À!?Qè¨Ù¦vr¶€Eù šË¹{_xë/�ƒ¹¯Qc‘ÊŠÞ-¹¬0D¿ÎŠC<`€÷áÍ䦩BrÄ~5¨ï"ÅcYRë
3-ÊDžm‹`V]©PtÌ.Øqh®"x·wñ¾…#li㬹…1å]ìÙzÌD£P=
„f.$ýYÆå¿ao“¤žýŸ…B’sVX»ÏVꊈ˜¤Üî0O¹pÍ
msUIUªÞĽ0äÄ»ÃK¤ÁÞ¯¼°?Û�w_…î¶HHϰ”z�zåD2üÂROs ±ÕMÑÒŒ•°[+Ìhû¤:ׂyõÁ 7#{uÞOÇüƒèùZÝQÉvá–{#™žÏôGÂCÕ;)6Pl\ì/¸@ê
;)ڽʬ)³ã‡œ…Ø›ÿhŒ—e*‰ÿóeE
e�ñʉCç×n{ƒ3)
{‰ÏÈZZ-ûS�4Ác�Žˆ� L9¥3b ïV‹ŽŒ~OÉÜÌ6hbå)VY‚ù;Ë?…À›É]ëõ/™s“öÅž/4å#Á}Ø€8x{É”GF3Ö›DK�F·‹»Ê‹T5[ܨ©ó+×)à#ðAP@*jÉ/Œ‘¦ùÐ�½B[«v²ïèoHæTòêK,®Gî×:ÿÍj,ÜžõIa_âÏf¡½‹éú2)ÞD`J0¯Ô!ÓÓ·\÷Q†uïÎÛ‘Ë!j4ÖCìçÚßéàBÃ4«¿tßë½,Q7rzíü>BñDÃ\4ó!n߸·@=Ñ,¬
P¸Ÿ#«}vÉ"¶ázB{¨à»£È“EÃ�÷
|
||||||
|
¥®âלë‚ÏÆiªr×ùC&&«)ãÃÐ}ÕQºùäÈÒ½÷\¸×ÜRÈð,˜Ù±A_C®ìò�ƒÃÒáSIÇ€³\êî¡dB«Þbäz�Q&êûÑ”»iJÅ~�|^þÂYœz* çb¯ ˵Tó±Èëºby:˜ÌtÂ�ÖÅYÙ8�5ž
ò¼ö汘ÿ[‚Gfïa[úlËnaoQý8ÿÊÿŠ2Yeê¡$+òŠâ=ø³&Óîf1!ÿ.wAÀj#÷¨‚`šæBY[è>Cî¨T>àt×PÝDH[ÒÇ�Ø}³|1dñÞ�y£ƒ%•m8'COtWz·G‹rÏa¯¢C³%Œï²K¹/p:¤,²ò2�vY˸—(�Ö[ðr7wE=7ÅÝÖd³¢¡€/‡È«`'Òdj×»³†§Øƒ
|
||||||
|
Ìþg
|
||||||
|
½Â1hÑtÃ'ò‚Ågª5›C�™.-A•ÓH¸4Q«Cæ‘QŠ6Š�ˆN‚²ò°VWi5WC�hÐvól·ø jeÔ?«”˜
|
||||||
|
eg6R¡œ§óÒßö3‹^ËJÍÁ¥‰n{´“39qÑäý_�½L6Ž^6§Ÿó•<Lƒ‰-,apj =‹\`ÿ*#KÆ|‰?ŒþVÿN•ƒ;G¦Ä¢¸�
C�à¥ÝyúlÏ»ÎGüYÎêd/§'æt$øÍ%…1J çô×ÑB§4õ²• <
|
||||||
|
¿Ê�BÇášÜ›Sላ?
|
||||||
@@ -90,6 +90,18 @@ impl PartialEq<&[u8; 4]> for PropTag {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PartialEq<String> for PropTag {
|
||||||
|
fn eq(&self, other: &String) -> bool {
|
||||||
|
self.tag == other.as_bytes()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq<&str> for PropTag {
|
||||||
|
fn eq(&self, other: &&str) -> bool {
|
||||||
|
self.tag == other.as_bytes()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ExtraProp {
|
impl ExtraProp {
|
||||||
pub fn is_filename_hash(&self) -> bool {
|
pub fn is_filename_hash(&self) -> bool {
|
||||||
self.tag == CHUNK_HNFN
|
self.tag == CHUNK_HNFN
|
||||||
|
|||||||
@@ -8,13 +8,13 @@ const S_CTL_BLOCK_SIGNATURE: &[u8] = b" Encryption control block";
|
|||||||
macro_rules! base_schema_impl {
|
macro_rules! base_schema_impl {
|
||||||
() => {
|
() => {
|
||||||
fn hash_after_crypt(&self) -> bool {
|
fn hash_after_crypt(&self) -> bool {
|
||||||
self.base.hash_after_crypt
|
AsRef::<BaseSchema>::as_ref(self.as_ref()).hash_after_crypt
|
||||||
}
|
}
|
||||||
fn startup_tjs_not_encrypted(&self) -> bool {
|
fn startup_tjs_not_encrypted(&self) -> bool {
|
||||||
self.base.startup_tjs_not_encrypted
|
AsRef::<BaseSchema>::as_ref(self.as_ref()).startup_tjs_not_encrypted
|
||||||
}
|
}
|
||||||
fn obfuscated_index(&self) -> bool {
|
fn obfuscated_index(&self) -> bool {
|
||||||
self.base.obfuscated_index
|
AsRef::<BaseSchema>::as_ref(self.as_ref()).obfuscated_index
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -27,12 +27,60 @@ pub struct CxEncryption {
|
|||||||
odd_branch_order: Vec<u8>,
|
odd_branch_order: Vec<u8>,
|
||||||
even_branch_order: Vec<u8>,
|
even_branch_order: Vec<u8>,
|
||||||
control_block: Arc<Vec<u32>>,
|
control_block: Arc<Vec<u32>>,
|
||||||
programs: Vec<CxProgram>,
|
programs: Vec<Box<dyn ICxProgram>>,
|
||||||
|
program_builder: Box<dyn ICxProgramBuilder>,
|
||||||
base: BaseSchema,
|
base: BaseSchema,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trait ICxEncryption: std::fmt::Debug {
|
||||||
|
fn get_base_offset(&self, hash: u32) -> u32;
|
||||||
|
fn inner_decrypt(
|
||||||
|
&self,
|
||||||
|
mut key: u32,
|
||||||
|
mut offset: u64,
|
||||||
|
buffer: &mut [u8],
|
||||||
|
mut pos: usize,
|
||||||
|
mut count: usize,
|
||||||
|
) -> Result<()> {
|
||||||
|
let base_offset = self.get_base_offset(key);
|
||||||
|
if offset < base_offset as u64 {
|
||||||
|
let base_length = ((base_offset as u64 - offset) as usize).min(count);
|
||||||
|
self.decode(key, offset, buffer, pos, base_length)?;
|
||||||
|
offset += base_length as u64;
|
||||||
|
pos += base_length;
|
||||||
|
count -= base_length;
|
||||||
|
}
|
||||||
|
if count > 0 {
|
||||||
|
key = (key >> 16) ^ key;
|
||||||
|
self.decode(key, offset, buffer, pos, count)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
fn decode(
|
||||||
|
&self,
|
||||||
|
key: u32,
|
||||||
|
offset: u64,
|
||||||
|
buffer: &mut [u8],
|
||||||
|
pos: usize,
|
||||||
|
count: usize,
|
||||||
|
) -> Result<()>;
|
||||||
|
}
|
||||||
|
|
||||||
impl CxEncryption {
|
impl CxEncryption {
|
||||||
pub fn new(base: BaseSchema, schema: &CxSchema, filename: &str) -> Result<Arc<Self>> {
|
pub fn new(base: BaseSchema, schema: &CxSchema, filename: &str) -> Result<Arc<Self>> {
|
||||||
|
Ok(Arc::new(Self::new_inner(
|
||||||
|
base,
|
||||||
|
schema,
|
||||||
|
filename,
|
||||||
|
Box::new(CxProgramBuilder::default()),
|
||||||
|
)?))
|
||||||
|
}
|
||||||
|
fn new_inner(
|
||||||
|
base: BaseSchema,
|
||||||
|
schema: &CxSchema,
|
||||||
|
filename: &str,
|
||||||
|
program_builder: Box<dyn ICxProgramBuilder>,
|
||||||
|
) -> Result<Self> {
|
||||||
if schema.prolog_order.len() != 3 {
|
if schema.prolog_order.len() != 3 {
|
||||||
return Err(anyhow::anyhow!("Prolog order must have 3 elements"));
|
return Err(anyhow::anyhow!("Prolog order must have 3 elements"));
|
||||||
}
|
}
|
||||||
@@ -70,23 +118,20 @@ impl CxEncryption {
|
|||||||
even_branch_order: schema.even_branch_order.bytes.clone(),
|
even_branch_order: schema.even_branch_order.bytes.clone(),
|
||||||
control_block: control_block,
|
control_block: control_block,
|
||||||
programs,
|
programs,
|
||||||
|
program_builder,
|
||||||
};
|
};
|
||||||
for seed in 0..0x80 {
|
for seed in 0..0x80 {
|
||||||
obj.programs.push(obj.generate_program(seed)?);
|
obj.programs.push(obj.generate_program(seed)?);
|
||||||
}
|
}
|
||||||
Ok(Arc::new(obj))
|
Ok(obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_program(&self, seed: u32) -> CxProgram {
|
fn new_program(&self, seed: u32) -> Box<dyn ICxProgram> {
|
||||||
CxProgram {
|
self.program_builder
|
||||||
code: Vec::with_capacity(CX_PROGRAM_SIZE),
|
.build(seed, Arc::downgrade(&self.control_block))
|
||||||
control_block: Arc::downgrade(&self.control_block),
|
|
||||||
length: 0,
|
|
||||||
seed,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_program(&self, seed: u32) -> Result<CxProgram> {
|
fn generate_program(&self, seed: u32) -> Result<Box<dyn ICxProgram>> {
|
||||||
let mut program = self.new_program(seed);
|
let mut program = self.new_program(seed);
|
||||||
for stage in (1..=5).rev() {
|
for stage in (1..=5).rev() {
|
||||||
if self.emit_code(&mut program, stage) {
|
if self.emit_code(&mut program, stage) {
|
||||||
@@ -135,7 +180,7 @@ impl CxEncryption {
|
|||||||
Err(anyhow::anyhow!("TPM file not found: {}", tpm_path))
|
Err(anyhow::anyhow!("TPM file not found: {}", tpm_path))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_code(&self, program: &mut CxProgram, stage: i32) -> bool {
|
fn emit_code(&self, program: &mut Box<dyn ICxProgram>, stage: i32) -> bool {
|
||||||
program.emit_nop(5)
|
program.emit_nop(5)
|
||||||
&& program.emit(MovEdiArg, 4)
|
&& program.emit(MovEdiArg, 4)
|
||||||
&& self.emit_body(program, stage)
|
&& self.emit_body(program, stage)
|
||||||
@@ -143,7 +188,7 @@ impl CxEncryption {
|
|||||||
&& program.emit(Retn, 1)
|
&& program.emit(Retn, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_body(&self, program: &mut CxProgram, stage: i32) -> bool {
|
fn emit_body(&self, program: &mut Box<dyn ICxProgram>, stage: i32) -> bool {
|
||||||
if stage == 1 {
|
if stage == 1 {
|
||||||
return self.emit_prolog(program);
|
return self.emit_prolog(program);
|
||||||
}
|
}
|
||||||
@@ -174,7 +219,7 @@ impl CxEncryption {
|
|||||||
self.emit_odd_branch(program) && program.emit(PopEbx, 1)
|
self.emit_odd_branch(program) && program.emit(PopEbx, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_body2(&self, program: &mut CxProgram, stage: i32) -> bool {
|
fn emit_body2(&self, program: &mut Box<dyn ICxProgram>, stage: i32) -> bool {
|
||||||
if stage == 1 {
|
if stage == 1 {
|
||||||
return self.emit_prolog(program);
|
return self.emit_prolog(program);
|
||||||
}
|
}
|
||||||
@@ -185,7 +230,7 @@ impl CxEncryption {
|
|||||||
};
|
};
|
||||||
r && self.emit_even_branch(program)
|
r && self.emit_even_branch(program)
|
||||||
}
|
}
|
||||||
fn emit_prolog(&self, program: &mut CxProgram) -> bool {
|
fn emit_prolog(&self, program: &mut Box<dyn ICxProgram>) -> bool {
|
||||||
match self.prolog_order[(program.get_random() % 3) as usize] {
|
match self.prolog_order[(program.get_random() % 3) as usize] {
|
||||||
2 => {
|
2 => {
|
||||||
program.emit_nop(5)
|
program.emit_nop(5)
|
||||||
@@ -202,7 +247,7 @@ impl CxEncryption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_even_branch(&self, program: &mut CxProgram) -> bool {
|
fn emit_even_branch(&self, program: &mut Box<dyn ICxProgram>) -> bool {
|
||||||
match self.even_branch_order[(program.get_random() & 7) as usize] {
|
match self.even_branch_order[(program.get_random() & 7) as usize] {
|
||||||
0 => program.emit(NotEax, 2),
|
0 => program.emit(NotEax, 2),
|
||||||
1 => program.emit(DecEax, 1),
|
1 => program.emit(DecEax, 1),
|
||||||
@@ -240,7 +285,7 @@ impl CxEncryption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_odd_branch(&self, program: &mut CxProgram) -> bool {
|
fn emit_odd_branch(&self, program: &mut Box<dyn ICxProgram>) -> bool {
|
||||||
match self.odd_branch_order[(program.get_random() % 6) as usize] {
|
match self.odd_branch_order[(program.get_random() % 6) as usize] {
|
||||||
0 => {
|
0 => {
|
||||||
program.emit(PushEcx, 1)
|
program.emit(PushEcx, 1)
|
||||||
@@ -264,10 +309,6 @@ impl CxEncryption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_base_offset(&self, hash: u32) -> u32 {
|
|
||||||
(hash & self.mask).wrapping_add(self.offset)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn execute_xcode(&self, mut hash: u32) -> Result<(u32, u32)> {
|
fn execute_xcode(&self, mut hash: u32) -> Result<(u32, u32)> {
|
||||||
let seed = hash & 0x7f;
|
let seed = hash & 0x7f;
|
||||||
hash >>= 7;
|
hash >>= 7;
|
||||||
@@ -276,28 +317,17 @@ impl CxEncryption {
|
|||||||
let ret2 = program.execute(!hash)?;
|
let ret2 = program.execute(!hash)?;
|
||||||
Ok((ret1, ret2))
|
Ok((ret1, ret2))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn inner_decrypt(
|
impl AsRef<BaseSchema> for CxEncryption {
|
||||||
&self,
|
fn as_ref(&self) -> &BaseSchema {
|
||||||
mut key: u32,
|
&self.base
|
||||||
mut offset: u64,
|
}
|
||||||
buffer: &mut [u8],
|
}
|
||||||
mut pos: usize,
|
|
||||||
mut count: usize,
|
impl ICxEncryption for CxEncryption {
|
||||||
) -> Result<()> {
|
fn get_base_offset(&self, hash: u32) -> u32 {
|
||||||
let base_offset = self.get_base_offset(key);
|
(hash & self.mask).wrapping_add(self.offset)
|
||||||
if offset < base_offset as u64 {
|
|
||||||
let base_length = ((base_offset as u64 - offset) as usize).min(count);
|
|
||||||
self.decode(key, offset, buffer, pos, base_length)?;
|
|
||||||
offset += base_length as u64;
|
|
||||||
pos += base_length;
|
|
||||||
count -= base_length;
|
|
||||||
}
|
|
||||||
if count > 0 {
|
|
||||||
key = (key >> 16) ^ key;
|
|
||||||
self.decode(key, offset, buffer, pos, count)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode(
|
fn decode(
|
||||||
@@ -331,6 +361,68 @@ impl CxEncryption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! icx_enc_arc_impl {
|
||||||
|
($t:ident) => {
|
||||||
|
impl ICxEncryption for Arc<$t> {
|
||||||
|
fn get_base_offset(&self, hash: u32) -> u32 {
|
||||||
|
self.as_ref().get_base_offset(hash)
|
||||||
|
}
|
||||||
|
fn inner_decrypt(
|
||||||
|
&self,
|
||||||
|
key: u32,
|
||||||
|
offset: u64,
|
||||||
|
buffer: &mut [u8],
|
||||||
|
pos: usize,
|
||||||
|
count: usize,
|
||||||
|
) -> Result<()> {
|
||||||
|
self.as_ref().inner_decrypt(key, offset, buffer, pos, count)
|
||||||
|
}
|
||||||
|
fn decode(
|
||||||
|
&self,
|
||||||
|
key: u32,
|
||||||
|
offset: u64,
|
||||||
|
buffer: &mut [u8],
|
||||||
|
pos: usize,
|
||||||
|
count: usize,
|
||||||
|
) -> Result<()> {
|
||||||
|
self.as_ref().decode(key, offset, buffer, pos, count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! icx_enc_impl {
|
||||||
|
($t:ident) => {
|
||||||
|
impl ICxEncryption for $t {
|
||||||
|
fn get_base_offset(&self, hash: u32) -> u32 {
|
||||||
|
self.base.get_base_offset(hash)
|
||||||
|
}
|
||||||
|
fn inner_decrypt(
|
||||||
|
&self,
|
||||||
|
key: u32,
|
||||||
|
offset: u64,
|
||||||
|
buffer: &mut [u8],
|
||||||
|
pos: usize,
|
||||||
|
count: usize,
|
||||||
|
) -> Result<()> {
|
||||||
|
self.base.inner_decrypt(key, offset, buffer, pos, count)
|
||||||
|
}
|
||||||
|
fn decode(
|
||||||
|
&self,
|
||||||
|
key: u32,
|
||||||
|
offset: u64,
|
||||||
|
buffer: &mut [u8],
|
||||||
|
pos: usize,
|
||||||
|
count: usize,
|
||||||
|
) -> Result<()> {
|
||||||
|
self.base.decode(key, offset, buffer, pos, count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
icx_enc_arc_impl!(CxEncryption);
|
||||||
|
|
||||||
impl Crypt for Arc<CxEncryption> {
|
impl Crypt for Arc<CxEncryption> {
|
||||||
base_schema_impl!();
|
base_schema_impl!();
|
||||||
fn decrypt_supported(&self) -> bool {
|
fn decrypt_supported(&self) -> bool {
|
||||||
@@ -345,7 +437,10 @@ impl Crypt for Arc<CxEncryption> {
|
|||||||
cur_seg: &Segment,
|
cur_seg: &Segment,
|
||||||
stream: Box<dyn Read + 'a>,
|
stream: Box<dyn Read + 'a>,
|
||||||
) -> Result<Box<dyn ReadDebug + 'a>> {
|
) -> Result<Box<dyn ReadDebug + 'a>> {
|
||||||
let key = (entry.file_hash, self.clone());
|
let key = (
|
||||||
|
entry.file_hash,
|
||||||
|
Box::new(self.clone()) as Box<dyn ICxEncryption + 'a>,
|
||||||
|
);
|
||||||
Ok(Box::new(CxEncryptionReader::new(stream, cur_seg, key)))
|
Ok(Box::new(CxEncryptionReader::new(stream, cur_seg, key)))
|
||||||
}
|
}
|
||||||
fn decrypt_with_seek<'a>(
|
fn decrypt_with_seek<'a>(
|
||||||
@@ -354,7 +449,10 @@ impl Crypt for Arc<CxEncryption> {
|
|||||||
cur_seg: &Segment,
|
cur_seg: &Segment,
|
||||||
stream: Box<dyn ReadSeek + 'a>,
|
stream: Box<dyn ReadSeek + 'a>,
|
||||||
) -> Result<Box<dyn ReadSeek + 'a>> {
|
) -> Result<Box<dyn ReadSeek + 'a>> {
|
||||||
let key = (entry.file_hash, self.clone());
|
let key = (
|
||||||
|
entry.file_hash,
|
||||||
|
Box::new(self.clone()) as Box<dyn ICxEncryption + 'a>,
|
||||||
|
);
|
||||||
Ok(Box::new(CxEncryptionReader::new(stream, cur_seg, key)))
|
Ok(Box::new(CxEncryptionReader::new(stream, cur_seg, key)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -418,7 +516,41 @@ struct Context {
|
|||||||
stack: Vec<u32>,
|
stack: Vec<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CxProgram {
|
#[derive(Debug)]
|
||||||
|
struct CxProgramBuilder {}
|
||||||
|
|
||||||
|
impl Default for CxProgramBuilder {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait ICxProgramBuilder: std::fmt::Debug {
|
||||||
|
fn build(&self, seed: u32, control_blocks: Weak<Vec<u32>>) -> Box<dyn ICxProgram>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ICxProgramBuilder for CxProgramBuilder {
|
||||||
|
fn build(&self, seed: u32, control_blocks: Weak<Vec<u32>>) -> Box<dyn ICxProgram> {
|
||||||
|
Box::new(CxProgram {
|
||||||
|
code: Vec::with_capacity(CX_PROGRAM_SIZE),
|
||||||
|
control_block: control_blocks,
|
||||||
|
length: 0,
|
||||||
|
seed,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trait ICxProgram: std::fmt::Debug {
|
||||||
|
fn execute(&self, hash: u32) -> Result<u32>;
|
||||||
|
fn clear(&mut self);
|
||||||
|
fn emit_nop(&mut self, count: usize) -> bool;
|
||||||
|
fn emit(&mut self, bytecode: CxByteCode, length: usize) -> bool;
|
||||||
|
fn emit_u32(&mut self, x: u32) -> bool;
|
||||||
|
fn emit_random(&mut self) -> bool;
|
||||||
|
fn get_random(&mut self) -> u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ICxProgram for CxProgram {
|
||||||
fn execute(&self, hash: u32) -> Result<u32> {
|
fn execute(&self, hash: u32) -> Result<u32> {
|
||||||
let mut context = Context::default();
|
let mut context = Context::default();
|
||||||
let mut iterator = self.code.iter();
|
let mut iterator = self.code.iter();
|
||||||
@@ -602,7 +734,45 @@ impl CxProgram {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: Read> Read for CxEncryptionReader<R> {
|
#[derive(msg_tool_macro::MyDebug)]
|
||||||
|
struct CxEncryptionReader<'a, T> {
|
||||||
|
#[skip_fmt]
|
||||||
|
inner: T,
|
||||||
|
seg_start: u64,
|
||||||
|
seg_size: u64,
|
||||||
|
pos: u64,
|
||||||
|
key: (u32, Box<dyn ICxEncryption + 'a>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: Read> CxEncryptionReader<'a, T> {
|
||||||
|
pub fn new(inner: T, seg: &Segment, key: (u32, Box<dyn ICxEncryption + 'a>)) -> Self {
|
||||||
|
Self {
|
||||||
|
inner,
|
||||||
|
seg_start: seg.offset_in_file,
|
||||||
|
seg_size: seg.original_size,
|
||||||
|
pos: 0,
|
||||||
|
key,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T: Read + Seek> Seek for CxEncryptionReader<'a, T> {
|
||||||
|
fn seek(&mut self, pos: SeekFrom) -> std::io::Result<u64> {
|
||||||
|
let new_pos: i64 = match pos {
|
||||||
|
SeekFrom::Start(offset) => offset as i64,
|
||||||
|
SeekFrom::End(offset) => self.seg_size as i64 + offset,
|
||||||
|
SeekFrom::Current(offset) => self.pos as i64 + offset,
|
||||||
|
};
|
||||||
|
let offset = new_pos - self.pos as i64;
|
||||||
|
if offset != 0 {
|
||||||
|
self.inner.seek(SeekFrom::Current(offset))?;
|
||||||
|
self.pos = new_pos as u64;
|
||||||
|
}
|
||||||
|
Ok(self.pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, R: Read> Read for CxEncryptionReader<'a, R> {
|
||||||
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||||
let offset = self.seg_start + self.pos;
|
let offset = self.seg_start + self.pos;
|
||||||
let count = self.inner.read(buf)?;
|
let count = self.inner.read(buf)?;
|
||||||
@@ -618,3 +788,140 @@ impl<R: Read> Read for CxEncryptionReader<R> {
|
|||||||
Ok(count)
|
Ok(count)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct SenrenCxCrypt {
|
||||||
|
base: CxEncryption,
|
||||||
|
names_section_id: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<BaseSchema> for SenrenCxCrypt {
|
||||||
|
fn as_ref(&self) -> &BaseSchema {
|
||||||
|
self.base.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SenrenCxCrypt {
|
||||||
|
pub fn new(
|
||||||
|
base: BaseSchema,
|
||||||
|
schema: &CxSchema,
|
||||||
|
filename: &str,
|
||||||
|
names_section_id: String,
|
||||||
|
) -> Result<Arc<Self>> {
|
||||||
|
Ok(Arc::new(Self::new_inner(
|
||||||
|
base,
|
||||||
|
schema,
|
||||||
|
filename,
|
||||||
|
Box::new(CxProgramBuilder::default()),
|
||||||
|
names_section_id,
|
||||||
|
)?))
|
||||||
|
}
|
||||||
|
fn new_inner(
|
||||||
|
base: BaseSchema,
|
||||||
|
schema: &CxSchema,
|
||||||
|
filename: &str,
|
||||||
|
program_builder: Box<dyn ICxProgramBuilder>,
|
||||||
|
names_section_id: String,
|
||||||
|
) -> Result<Self> {
|
||||||
|
let cx = CxEncryption::new_inner(base, schema, filename, program_builder)?;
|
||||||
|
Ok(Self {
|
||||||
|
base: cx,
|
||||||
|
names_section_id,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
fn read_yuzu_names(&self, archive: &mut Xp3Archive) -> Result<()> {
|
||||||
|
if let Some(section) = archive
|
||||||
|
.extras
|
||||||
|
.iter()
|
||||||
|
.find(|s| s.tag == self.names_section_id)
|
||||||
|
{
|
||||||
|
let mut sreader = MemReaderRef::new(§ion.data);
|
||||||
|
let offset = sreader.read_u64()? + archive.base_offset;
|
||||||
|
let unpacked_size = sreader.read_u32()?;
|
||||||
|
let packed_size = sreader.read_u32()?;
|
||||||
|
let index_stream =
|
||||||
|
MutexWrapper::new(archive.inner.clone(), offset).take(packed_size as u64);
|
||||||
|
let mut decoded = MemWriter::from_vec(Vec::with_capacity(unpacked_size as usize));
|
||||||
|
{
|
||||||
|
let mut decoder = flate2::read::ZlibDecoder::new(index_stream);
|
||||||
|
std::io::copy(&mut decoder, &mut decoded)?;
|
||||||
|
}
|
||||||
|
let decoded = decoded.into_inner();
|
||||||
|
let mut reader = MemReader::new(decoded);
|
||||||
|
let mut hash_map = HashMap::new();
|
||||||
|
let mut md5_map = HashMap::new();
|
||||||
|
let mut dir_offset = 0u64;
|
||||||
|
while !reader.is_eof() {
|
||||||
|
let _entry_sign = reader.read_u32()?;
|
||||||
|
let mut entry_size = reader.read_u64()?;
|
||||||
|
dir_offset += 12 + entry_size;
|
||||||
|
let hash = reader.read_u32()?;
|
||||||
|
let name_len = reader.read_u16()?;
|
||||||
|
entry_size -= 6;
|
||||||
|
if (name_len as u64) * 2 <= entry_size {
|
||||||
|
let name = reader.read_exact_vec((name_len) as usize * 2)?;
|
||||||
|
let name = decode_to_string(Encoding::Utf16LE, &name, true)?;
|
||||||
|
if !hash_map.contains_key(&hash) {
|
||||||
|
hash_map.insert(hash, name.clone());
|
||||||
|
}
|
||||||
|
let encoded =
|
||||||
|
encode_string(Encoding::Utf16LE, &name.to_ascii_lowercase(), true)?;
|
||||||
|
let md5 = format!("{:x}", md5::compute(encoded));
|
||||||
|
md5_map.insert(md5, name);
|
||||||
|
}
|
||||||
|
reader.pos = dir_offset as usize;
|
||||||
|
md5_map.insert("$".into(), "startup.tjs".into());
|
||||||
|
}
|
||||||
|
for entry in archive.entries.iter_mut() {
|
||||||
|
if let Some(name) = hash_map.get(&entry.file_hash) {
|
||||||
|
entry.name = name.clone();
|
||||||
|
} else if let Some(name) = md5_map.get(&entry.name) {
|
||||||
|
entry.name = name.clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
archive.extras.retain(|s| s.tag != self.names_section_id);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
icx_enc_impl!(SenrenCxCrypt);
|
||||||
|
icx_enc_arc_impl!(SenrenCxCrypt);
|
||||||
|
|
||||||
|
impl Crypt for Arc<SenrenCxCrypt> {
|
||||||
|
base_schema_impl!();
|
||||||
|
fn init(&self, archive: &mut Xp3Archive) -> Result<()> {
|
||||||
|
default_init_crypt(archive)?;
|
||||||
|
self.read_yuzu_names(archive)
|
||||||
|
}
|
||||||
|
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>> {
|
||||||
|
let key = (
|
||||||
|
entry.file_hash,
|
||||||
|
Box::new(self.clone()) as Box<dyn ICxEncryption + 'a>,
|
||||||
|
);
|
||||||
|
Ok(Box::new(CxEncryptionReader::new(stream, cur_seg, key)))
|
||||||
|
}
|
||||||
|
fn decrypt_with_seek<'a>(
|
||||||
|
&self,
|
||||||
|
entry: &Xp3Entry,
|
||||||
|
cur_seg: &Segment,
|
||||||
|
stream: Box<dyn ReadSeek + 'a>,
|
||||||
|
) -> Result<Box<dyn ReadSeek + 'a>> {
|
||||||
|
let key = (
|
||||||
|
entry.file_hash,
|
||||||
|
Box::new(self.clone()) as Box<dyn ICxEncryption + 'a>,
|
||||||
|
);
|
||||||
|
Ok(Box::new(CxEncryptionReader::new(stream, cur_seg, key)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -124,6 +124,12 @@ enum CryptType {
|
|||||||
},
|
},
|
||||||
FlyingShineCrypt,
|
FlyingShineCrypt,
|
||||||
CxEncryption(CxSchema),
|
CxEncryption(CxSchema),
|
||||||
|
#[serde(rename_all = "PascalCase")]
|
||||||
|
SenrenCxCrypt {
|
||||||
|
#[serde(flatten)]
|
||||||
|
cx: CxSchema,
|
||||||
|
names_section_id: String,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize)]
|
#[derive(Clone, Debug, Deserialize)]
|
||||||
@@ -159,6 +165,15 @@ impl Schema {
|
|||||||
CryptType::CxEncryption(schema) => {
|
CryptType::CxEncryption(schema) => {
|
||||||
Box::new(cx::CxEncryption::new(self.base.clone(), &schema, filename)?)
|
Box::new(cx::CxEncryption::new(self.base.clone(), &schema, filename)?)
|
||||||
}
|
}
|
||||||
|
CryptType::SenrenCxCrypt {
|
||||||
|
cx,
|
||||||
|
names_section_id,
|
||||||
|
} => Box::new(cx::SenrenCxCrypt::new(
|
||||||
|
self.base.clone(),
|
||||||
|
cx,
|
||||||
|
filename,
|
||||||
|
names_section_id.clone(),
|
||||||
|
)?),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -601,9 +616,6 @@ impl<R: Read> Read for FlyingShineCryptReader<R> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// extended in cx.rs
|
|
||||||
seek_reader_key_impl!(CxEncryptionReader<T>, (u32, Arc<cx::CxEncryption>));
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_deserialize_crypt() {
|
fn test_deserialize_crypt() {
|
||||||
for (key, schema) in CRYPT_SCHEMA.iter() {
|
for (key, schema) in CRYPT_SCHEMA.iter() {
|
||||||
|
|||||||
Reference in New Issue
Block a user