139 lines
3.7 KiB
C#
139 lines
3.7 KiB
C#
using System;
|
|
|
|
namespace ClHcaSharp
|
|
{
|
|
internal static class Cipher
|
|
{
|
|
public static void Decrypt(byte[] cipherData, byte[] data)
|
|
{
|
|
for (int i = 0; i < data.Length; i++)
|
|
{
|
|
data[i] = cipherData[data[i]];
|
|
}
|
|
}
|
|
|
|
public static byte[] Init(int type, ulong keyCode)
|
|
{
|
|
if (type == 56 && keyCode == 0) type = 0;
|
|
|
|
return type switch
|
|
{
|
|
0 => Init0(),
|
|
1 => Init1(),
|
|
56 => Init56(keyCode),
|
|
_ => throw new ArgumentException("Invalid cipher type."),
|
|
};
|
|
}
|
|
|
|
private static byte[] Init0()
|
|
{
|
|
byte[] cipherTable = new byte[256];
|
|
|
|
for (int i = 0; i < 256; i++)
|
|
{
|
|
cipherTable[i] = (byte)i;
|
|
}
|
|
|
|
return cipherTable;
|
|
}
|
|
|
|
private static byte[] Init1()
|
|
{
|
|
byte[] cipherTable = new byte[256];
|
|
|
|
const int mul = 13;
|
|
const int add = 11;
|
|
|
|
uint v = 0;
|
|
for (int i = 1; i < 256 - 1; i++)
|
|
{
|
|
v = (v * mul + add) & 0xFF;
|
|
if (v == 0 || v == 0xFF)
|
|
v = (v * mul + add) & 0xFF;
|
|
cipherTable[i] = (byte)v;
|
|
}
|
|
cipherTable[0] = 0;
|
|
cipherTable[0xFF] = 0xFF;
|
|
|
|
return cipherTable;
|
|
}
|
|
|
|
private static void Init56CreateTable(byte[] table, byte key)
|
|
{
|
|
int mul = ((key & 1) << 3) | 5;
|
|
int add = (key & 0xE) | 1;
|
|
|
|
key >>= 4;
|
|
|
|
for (int i = 0; i < 16; i++)
|
|
{
|
|
key = (byte)((key * mul + add) & 0xF);
|
|
table[i] = key;
|
|
}
|
|
}
|
|
|
|
private static byte[] Init56(ulong keyCode)
|
|
{
|
|
byte[] cipherTable = new byte[256];
|
|
|
|
byte[] kc = new byte[8];
|
|
byte[] seed = new byte[16];
|
|
byte[] baseTable = new byte[256];
|
|
byte[] baseTableR = new byte[16];
|
|
byte[] baseTableC = new byte[16];
|
|
|
|
if (keyCode != 0) keyCode--;
|
|
|
|
for (int r = 0; r < (8 - 1); r++)
|
|
{
|
|
kc[r] = (byte)(keyCode & 0xFF);
|
|
keyCode >>= 8;
|
|
}
|
|
|
|
seed[0x00] = kc[1];
|
|
seed[0x01] = (byte)(kc[1] ^ kc[6]);
|
|
seed[0x02] = (byte)(kc[2] ^ kc[3]);
|
|
seed[0x03] = kc[2];
|
|
seed[0x04] = (byte)(kc[2] ^ kc[1]);
|
|
seed[0x05] = (byte)(kc[3] ^ kc[4]);
|
|
seed[0x06] = kc[3];
|
|
seed[0x07] = (byte)(kc[3] ^ kc[2]);
|
|
seed[0x08] = (byte)(kc[4] ^ kc[5]);
|
|
seed[0x09] = kc[4];
|
|
seed[0x0A] = (byte)(kc[4] ^ kc[3]);
|
|
seed[0x0B] = (byte)(kc[5] ^ kc[6]);
|
|
seed[0x0C] = kc[5];
|
|
seed[0x0D] = (byte)(kc[5] ^ kc[4]);
|
|
seed[0x0E] = (byte)(kc[6] ^ kc[1]);
|
|
seed[0x0F] = kc[6];
|
|
|
|
Init56CreateTable(baseTableR, kc[0]);
|
|
|
|
for (int r = 0; r < 16; r++)
|
|
{
|
|
byte nb;
|
|
Init56CreateTable(baseTableC, seed[r]);
|
|
nb = (byte)(baseTableR[r] << 4);
|
|
for (int c = 0; c < 16; c++)
|
|
{
|
|
baseTable[r * 16 + c] = (byte)(nb | baseTableC[c]);
|
|
}
|
|
}
|
|
|
|
uint x = 0;
|
|
uint pos = 1;
|
|
|
|
for (int i = 0; i < 256; i++)
|
|
{
|
|
x = (x + 17) & 0xFF;
|
|
if (baseTable[x] != 0 && baseTable[x] != 0xFF)
|
|
cipherTable[pos++] = baseTable[x];
|
|
}
|
|
|
|
cipherTable[0] = 0;
|
|
cipherTable[0xFF] = 0xFF;
|
|
|
|
return cipherTable;
|
|
}
|
|
}
|
|
} |