Files
YarikStudio/AssetStudio/Crypto/BlkUtils.cs
2023-09-19 13:22:50 +04:00

67 lines
2.1 KiB
C#

using System;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.Text;
namespace AssetStudio
{
public static class BlkUtils
{
private const int DataOffset = 0x2A;
private const int KeySize = 0x1000;
private const int SeedBlockSize = 0x800;
public static XORStream Decrypt(FileReader reader, Blk blk)
{
reader.Endian = EndianType.LittleEndian;
var signature = reader.ReadStringToNull();
Logger.Verbose($"Signature: {signature}");
var count = reader.ReadInt32();
Logger.Verbose($"Key size: {count}");
var key = reader.ReadBytes(count);
reader.Position += count;
var seedSize = Math.Min(reader.ReadInt16(), blk.SBox.IsNullOrEmpty() ? SeedBlockSize : SeedBlockSize * 2);
Logger.Verbose($"Seed size: 0x{seedSize:X8}");
if (!blk.SBox.IsNullOrEmpty() && blk.Type.IsGI())
{
for (int i = 0; i < 0x10; i++)
{
key[i] = blk.SBox[(i % 4 * 0x100) | key[i]];
}
}
AES.Decrypt(key, blk.ExpansionKey);
for (int i = 0; i < 0x10; i++)
{
key[i] ^= blk.InitVector[i];
}
ulong keySeed = ulong.MaxValue;
var dataPos = reader.Position;
for (int i = 0; i < seedSize; i += 8)
{
keySeed ^= reader.ReadUInt64();
}
reader.Position = dataPos;
var keyLow = BinaryPrimitives.ReadUInt64LittleEndian(key.AsSpan(0, 8));
var keyHigh = BinaryPrimitives.ReadUInt64LittleEndian(key.AsSpan(8, 8));
var seed = keyLow ^ keyHigh ^ keySeed ^ blk.InitSeed;
Logger.Verbose($"Seed: 0x{seed:X8}");
var mt64 = new MT19937_64(seed);
var xorpad = new byte[KeySize];
for (int i = 0; i < KeySize; i += 8)
{
BinaryPrimitives.WriteUInt64LittleEndian(xorpad.AsSpan(i, 8), mt64.Int64());
}
return new XORStream(reader.BaseStream, DataOffset, xorpad);
}
}
}