WzComparerR2-Plus/WzComparerR2.WzLib/Wz_Crypto.cs

329 lines
10 KiB
C#
Raw Normal View History

2022-01-14 12:35:16 +00:00
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Security.Cryptography;
using System.Collections.Specialized;
using System.Text.RegularExpressions;
namespace WzComparerR2.WzLib
{
public class Wz_Crypto
{
public Wz_Crypto()
{
this.keys_bms = new Wz_CryptoKey(iv_bms);
this.keys_kms = new Wz_CryptoKey(iv_kms);
this.keys_gms = new Wz_CryptoKey(iv_gms);
this.listwz = false;
this.EncType = Wz_CryptoKeyType.Unknown;
this.List = new StringCollection();
}
public void Reset()
{
this.encryption_detected = false;
this.listwz = false;
this.EncType = Wz_CryptoKeyType.Unknown;
this.List.Clear();
}
public bool list_contains(string name)
{
bool contains = this.List.Contains(name);
if (contains)
this.List.Remove(name);
return contains;
// foreach (string list_entry in this.list)
// {
// // if (list_entry.Contains(Name))
// if (list_entry == Name)
// {
// this.list.Remove(list_entry);
// return true;
// }
// }
// return false;
}
public void LoadListWz(string path)
{
path = Path.Combine(path, "List.wz");
if (File.Exists(path))
{
this.listwz = true;
using (FileStream list_file = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
{
BinaryReader listwz = new BinaryReader(list_file);
int length = (int)list_file.Length;
int len = 0;
byte b = 0;
string folder = "";
list_file.Position += 4;
byte check_for_d = listwz.ReadByte();
if ((char)(check_for_d ^ this.keys_gms[0]) == 'd')
{
this.EncType = Wz_CryptoKeyType.GMS;
}
else if ((char)(check_for_d ^ this.keys_kms[0]) == 'd')
{
this.EncType = Wz_CryptoKeyType.KMS;
}
list_file.Position = 0;
while (list_file.Position < length)
{
len = listwz.ReadInt32() * 2;
for (int i = 0; i < len; i += 2)
{
b = (byte)(listwz.ReadByte() ^ this.keys[i]);
folder += (char)(b);
list_file.Position++;
}
list_file.Position += 2;
folder.Replace(".im/", ".img");
this.List.Add(folder);
folder = "";
}
this.List.Remove("dummy");
}
}
}
public void DetectEncryption(Wz_File f)
{
int old_off = (int)f.FileStream.Position;
f.FileStream.Position = f.Header.DataStartPosition;
if (f.ReadInt32() <= 0) //只有文件头 无法预判
{
return;
}
f.FileStream.Position++;
int len = (int)(-f.BReader.ReadSByte());
byte[] bytes = f.BReader.ReadBytes(len);
for (int i = 0; i < len; i++)
{
bytes[i] ^= (byte)(0xAA + i);
}
StringBuilder sb = new StringBuilder();
if (!this.encryption_detected)
{
//测试bms
sb.Clear();
for (int i = 0; i < len; i++)
{
sb.Append((char)(keys_bms[i] ^ bytes[i]));
}
if (IsLegalNodeName(sb.ToString()))
{
this.EncType = Wz_CryptoKeyType.BMS;
this.encryption_detected = true;
goto lbl_end;
}
//测试kms
sb.Clear();
for (int i = 0; i < len; i++)
{
sb.Append((char)(keys_kms[i] ^ bytes[i]));
}
if (IsLegalNodeName(sb.ToString()))
{
this.EncType = Wz_CryptoKeyType.KMS;
this.encryption_detected = true;
goto lbl_end;
}
//测试gms
sb.Clear();
for (int i = 0; i < len; i++)
{
sb.Append((char)(keys_gms[i] ^ bytes[i]));
}
if (IsLegalNodeName(sb.ToString()))
{
this.EncType = Wz_CryptoKeyType.GMS;
this.encryption_detected = true;
goto lbl_end;
}
}
lbl_end:
f.FileStream.Position = old_off;
}
2022-04-06 03:04:29 +00:00
private bool IsLegalNodeName(string nodeName)
2022-01-14 12:35:16 +00:00
{
2022-04-06 03:04:29 +00:00
return nodeName.EndsWith(".img") || nodeName.EndsWith(".lua") || Regex.IsMatch(nodeName, @"^[A-Za-z0-9_]+$");
2022-01-14 12:35:16 +00:00
}
static readonly byte[] iv_gms = { 0x4d, 0x23, 0xc7, 0x2b };
static readonly byte[] iv_kms = { 0xb9, 0x7d, 0x63, 0xe9 };
static readonly byte[] iv_bms = { 0x00, 0x00, 0x00, 0x00 };
private Wz_CryptoKey keys_bms, keys_gms, keys_kms;
private Wz_CryptoKeyType enc_type;
public bool encryption_detected = false;
public bool listwz = false;
public Wz_CryptoKey keys { get; private set; }
public StringCollection List { get; private set; }
public Wz_CryptoKeyType EncType
{
get { return enc_type; }
set
{
enc_type = value;
switch (enc_type)
{
case Wz_CryptoKeyType.Unknown:
this.keys = null;
break;
case Wz_CryptoKeyType.BMS:
this.keys = keys_bms;
break;
case Wz_CryptoKeyType.KMS:
this.keys = keys_kms;
break;
case Wz_CryptoKeyType.GMS:
this.keys = keys_gms;
break;
}
}
}
public enum Wz_CryptoKeyType
{
Unknown = 0,
BMS = 1,
KMS = 2,
GMS = 3
}
public class Wz_CryptoKey
{
public Wz_CryptoKey(byte[] iv)
{
this.iv = iv;
if (iv == null || BitConverter.ToInt32(iv, 0) == 0)
{
this.isEmptyIV = true;
}
}
private byte[] keys;
private byte[] iv;
private bool isEmptyIV;
public byte this[int index]
{
get
{
if (isEmptyIV)
{
return 0;
}
if (keys == null || keys.Length <= index)
{
EnsureKeySize(index + 1);
}
return this.keys[index];
}
}
public void EnsureKeySize(int size)
{
if (isEmptyIV)
{
return;
}
if (this.keys != null && this.keys.Length >= size)
{
return;
}
size = (int)Math.Ceiling(1.0 * size / 4096) * 4096;
int startIndex = 0;
if (this.keys == null)
{
keys = new byte[size];
}
else
{
startIndex = this.keys.Length;
Array.Resize(ref this.keys, size);
}
Rijndael aes = Rijndael.Create();
aes.KeySize = 256;
aes.BlockSize = 128;
aes.Key = aesKey;
aes.Mode = CipherMode.ECB;
MemoryStream ms = new MemoryStream(keys, startIndex, keys.Length - startIndex, true);
CryptoStream s = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write);
for (int i = startIndex; i < size; i += 16)
{
if (i == 0)
{
byte[] block = new byte[16];
for (int j = 0; j < block.Length; j++)
{
block[j] = iv[j % 4];
}
s.Write(block, 0, block.Length);
}
else
{
s.Write(keys, i - 16, 16);
}
}
s.Flush();
ms.Close();
}
public unsafe void Decrypt(byte[] buffer, int startIndex, int length)
{
if (isEmptyIV)
return;
this.EnsureKeySize(length);
fixed (byte* pBuffer = buffer, pKeys = this.keys)
{
int i = 0;
byte* pData = pBuffer + startIndex;
for (int i1 = length / 4 * 4; i < i1; i += 4, pData += 4)
{
*((int*)pData) ^= *(int*)(pKeys + i);
}
for (; i < length; i++, pData++)
{
*pData ^= *(pKeys + i);
}
}
}
static readonly byte[] aesKey = {0x13, 0x00, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00,
0x06, 0x00, 0x00, 0x00,
0xB4, 0x00, 0x00, 0x00,
0x1B, 0x00, 0x00, 0x00,
0x0F, 0x00, 0x00, 0x00,
0x33, 0x00, 0x00, 0x00,
0x52, 0x00, 0x00, 0x00 };
}
}
2022-04-06 03:04:29 +00:00
}