From d2ea724c07f576523d155d218b4b9dec5c44e151 Mon Sep 17 00:00:00 2001 From: Crsky Date: Sat, 26 Nov 2022 01:09:18 +0800 Subject: [PATCH] Update HxCrypt implementation --- ArcFormats/KiriKiri/ArcXP3.cs | 2 +- ArcFormats/KiriKiri/HxCrypt.cs | 32 +++++++++++++++++++++++++++----- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/ArcFormats/KiriKiri/ArcXP3.cs b/ArcFormats/KiriKiri/ArcXP3.cs index d1a86199..2f4fc054 100644 --- a/ArcFormats/KiriKiri/ArcXP3.cs +++ b/ArcFormats/KiriKiri/ArcXP3.cs @@ -311,7 +311,7 @@ namespace GameRes.Formats.KiriKiri var flags = header.ReadUInt16 (); var hx = file.View.ReadBytes (offset, size); var crypt = crypt_algorithm.Value as HxCrypt; - hx_entry_info = crypt.ReadIndex (hx); + hx_entry_info = crypt.ReadIndex (Path.GetFileName (file.Name), hx); } catch (Exception) { /* ignore parse error */ } } diff --git a/ArcFormats/KiriKiri/HxCrypt.cs b/ArcFormats/KiriKiri/HxCrypt.cs index af809815..f8b543d3 100644 --- a/ArcFormats/KiriKiri/HxCrypt.cs +++ b/ArcFormats/KiriKiri/HxCrypt.cs @@ -36,6 +36,13 @@ using System.Text; namespace GameRes.Formats.KiriKiri { + [Serializable] + public class HxIndexKey + { + public byte[] Key1; // 32 bytes + public byte[] Key2; // 16 bytes + } + [Serializable] public class HxCrypt : CxEncryption { @@ -44,6 +51,7 @@ namespace GameRes.Formats.KiriKiri public ulong FilterKey; public int RandomType; public string NamesFile; + public Dictionary IndexKeyDict; public HxCrypt(CxScheme scheme) : base(scheme) { @@ -80,16 +88,26 @@ namespace GameRes.Formats.KiriKiri return new string(result); } - internal virtual Dictionary ReadIndex(byte[] data) + internal virtual Dictionary ReadIndex(string arc_name, byte[] data) { if (data.Length <= 20) // 16 + 4 return null; - if (null == IndexKey1 || IndexKey1.Length != 32) + var index_key1 = IndexKey1; + var index_key2 = IndexKey2; + if (null != IndexKeyDict) + { + if (IndexKeyDict.TryGetValue (arc_name, out HxIndexKey arc_index_key)) + { + index_key1 = arc_index_key.Key1; + index_key2 = arc_index_key.Key2; + } + } + if (null == index_key1 || index_key1.Length != 32) return null; - if (null == IndexKey2 || IndexKey2.Length != 16) + if (null == index_key2 || index_key2.Length != 16) return null; var seed = new uint[] { 1, 0 }; - var crypt = new HxChachaDecryptor (IndexKey1, IndexKey2, seed); + var crypt = new HxChachaDecryptor (index_key1, index_key2, seed); var buf = new byte[data.Length-16]; crypt.Decrypt (data, 16, buf, 0, buf.Length); Stream index_stream = null; @@ -154,6 +172,7 @@ namespace GameRes.Formats.KiriKiri entry_info.Name = name_str; entry_info.Key = (long)entry_key; var id = (uint)entry_id; + entry_info.Id = (long)entry_id; var uname = GetUnicodeName (id); entry_info_map.Add (uname, entry_info); } @@ -229,7 +248,9 @@ namespace GameRes.Formats.KiriKiri return; if (null != info.Filter) return; - var entry_key = (ulong)info.Key ^ FilterKey; + var entry_key = (ulong)info.Key; + if (0 == (info.Id & 0x100000000)) + entry_key ^= FilterKey; var header_key = ~entry_key; var key = CreateFilterKey (entry_key, header_key); info.Filter = new HxFilter (key); @@ -291,6 +312,7 @@ namespace GameRes.Formats.KiriKiri { public string Path; public string Name; + public long Id; public long Key; public HxFilter Filter; }