Update HxCrypt implementation

This commit is contained in:
Crsky
2022-11-26 01:09:18 +08:00
parent 069e05bf13
commit d2ea724c07
2 changed files with 28 additions and 6 deletions

View File

@@ -311,7 +311,7 @@ namespace GameRes.Formats.KiriKiri
var flags = header.ReadUInt16 (); var flags = header.ReadUInt16 ();
var hx = file.View.ReadBytes (offset, size); var hx = file.View.ReadBytes (offset, size);
var crypt = crypt_algorithm.Value as HxCrypt; 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 */ } catch (Exception) { /* ignore parse error */ }
} }

View File

@@ -36,6 +36,13 @@ using System.Text;
namespace GameRes.Formats.KiriKiri namespace GameRes.Formats.KiriKiri
{ {
[Serializable]
public class HxIndexKey
{
public byte[] Key1; // 32 bytes
public byte[] Key2; // 16 bytes
}
[Serializable] [Serializable]
public class HxCrypt : CxEncryption public class HxCrypt : CxEncryption
{ {
@@ -44,6 +51,7 @@ namespace GameRes.Formats.KiriKiri
public ulong FilterKey; public ulong FilterKey;
public int RandomType; public int RandomType;
public string NamesFile; public string NamesFile;
public Dictionary<string, HxIndexKey> IndexKeyDict;
public HxCrypt(CxScheme scheme) : base(scheme) public HxCrypt(CxScheme scheme) : base(scheme)
{ {
@@ -80,16 +88,26 @@ namespace GameRes.Formats.KiriKiri
return new string(result); return new string(result);
} }
internal virtual Dictionary<string, HxEntry> ReadIndex(byte[] data) internal virtual Dictionary<string, HxEntry> ReadIndex(string arc_name, byte[] data)
{ {
if (data.Length <= 20) // 16 + 4 if (data.Length <= 20) // 16 + 4
return null; 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; return null;
if (null == IndexKey2 || IndexKey2.Length != 16) if (null == index_key2 || index_key2.Length != 16)
return null; return null;
var seed = new uint[] { 1, 0 }; 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]; var buf = new byte[data.Length-16];
crypt.Decrypt (data, 16, buf, 0, buf.Length); crypt.Decrypt (data, 16, buf, 0, buf.Length);
Stream index_stream = null; Stream index_stream = null;
@@ -154,6 +172,7 @@ namespace GameRes.Formats.KiriKiri
entry_info.Name = name_str; entry_info.Name = name_str;
entry_info.Key = (long)entry_key; entry_info.Key = (long)entry_key;
var id = (uint)entry_id; var id = (uint)entry_id;
entry_info.Id = (long)entry_id;
var uname = GetUnicodeName (id); var uname = GetUnicodeName (id);
entry_info_map.Add (uname, entry_info); entry_info_map.Add (uname, entry_info);
} }
@@ -229,7 +248,9 @@ namespace GameRes.Formats.KiriKiri
return; return;
if (null != info.Filter) if (null != info.Filter)
return; 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 header_key = ~entry_key;
var key = CreateFilterKey (entry_key, header_key); var key = CreateFilterKey (entry_key, header_key);
info.Filter = new HxFilter (key); info.Filter = new HxFilter (key);
@@ -291,6 +312,7 @@ namespace GameRes.Formats.KiriKiri
{ {
public string Path; public string Path;
public string Name; public string Name;
public long Id;
public long Key; public long Key;
public HxFilter Filter; public HxFilter Filter;
} }