Files
SuperVPN/output/Libraries/BouncyCastle.Crypto/Org/BouncyCastle/Crypto/Engines/TwofishEngine.cs
2025-10-09 09:57:24 +09:00

475 lines
13 KiB
C#

using System;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Utilities;
namespace Org.BouncyCastle.Crypto.Engines;
public sealed class TwofishEngine : IBlockCipher
{
private const int P_00 = 1;
private const int P_01 = 0;
private const int P_02 = 0;
private const int P_03 = 1;
private const int P_04 = 1;
private const int P_10 = 0;
private const int P_11 = 0;
private const int P_12 = 1;
private const int P_13 = 1;
private const int P_14 = 0;
private const int P_20 = 1;
private const int P_21 = 1;
private const int P_22 = 0;
private const int P_23 = 0;
private const int P_24 = 0;
private const int P_30 = 0;
private const int P_31 = 1;
private const int P_32 = 1;
private const int P_33 = 0;
private const int P_34 = 1;
private const int GF256_FDBK = 361;
private const int GF256_FDBK_2 = 180;
private const int GF256_FDBK_4 = 90;
private const int RS_GF_FDBK = 333;
private const int ROUNDS = 16;
private const int MAX_ROUNDS = 16;
private const int BLOCK_SIZE = 16;
private const int MAX_KEY_BITS = 256;
private const int INPUT_WHITEN = 0;
private const int OUTPUT_WHITEN = 4;
private const int ROUND_SUBKEYS = 8;
private const int TOTAL_SUBKEYS = 40;
private const int SK_STEP = 33686018;
private const int SK_BUMP = 16843009;
private const int SK_ROTL = 9;
private static readonly byte[,] P = new byte[2, 256]
{
{
169, 103, 179, 232, 4, 253, 163, 118, 154, 146,
128, 120, 228, 221, 209, 56, 13, 198, 53, 152,
24, 247, 236, 108, 67, 117, 55, 38, 250, 19,
148, 72, 242, 208, 139, 48, 132, 84, 223, 35,
25, 91, 61, 89, 243, 174, 162, 130, 99, 1,
131, 46, 217, 81, 155, 124, 166, 235, 165, 190,
22, 12, 227, 97, 192, 140, 58, 245, 115, 44,
37, 11, 187, 78, 137, 107, 83, 106, 180, 241,
225, 230, 189, 69, 226, 244, 182, 102, 204, 149,
3, 86, 212, 28, 30, 215, 251, 195, 142, 181,
233, 207, 191, 186, 234, 119, 57, 175, 51, 201,
98, 113, 129, 121, 9, 173, 36, 205, 249, 216,
229, 197, 185, 77, 68, 8, 134, 231, 161, 29,
170, 237, 6, 112, 178, 210, 65, 123, 160, 17,
49, 194, 39, 144, 32, 246, 96, 255, 150, 92,
177, 171, 158, 156, 82, 27, 95, 147, 10, 239,
145, 133, 73, 238, 45, 79, 143, 59, 71, 135,
109, 70, 214, 62, 105, 100, 42, 206, 203, 47,
252, 151, 5, 122, 172, 127, 213, 26, 75, 14,
167, 90, 40, 20, 63, 41, 136, 60, 76, 2,
184, 218, 176, 23, 85, 31, 138, 125, 87, 199,
141, 116, 183, 196, 159, 114, 126, 21, 34, 18,
88, 7, 153, 52, 110, 80, 222, 104, 101, 188,
219, 248, 200, 168, 43, 64, 220, 254, 50, 164,
202, 16, 33, 240, 211, 93, 15, 0, 111, 157,
54, 66, 74, 94, 193, 224
},
{
117, 243, 198, 244, 219, 123, 251, 200, 74, 211,
230, 107, 69, 125, 232, 75, 214, 50, 216, 253,
55, 113, 241, 225, 48, 15, 248, 27, 135, 250,
6, 63, 94, 186, 174, 91, 138, 0, 188, 157,
109, 193, 177, 14, 128, 93, 210, 213, 160, 132,
7, 20, 181, 144, 44, 163, 178, 115, 76, 84,
146, 116, 54, 81, 56, 176, 189, 90, 252, 96,
98, 150, 108, 66, 247, 16, 124, 40, 39, 140,
19, 149, 156, 199, 36, 70, 59, 112, 202, 227,
133, 203, 17, 208, 147, 184, 166, 131, 32, 255,
159, 119, 195, 204, 3, 111, 8, 191, 64, 231,
43, 226, 121, 12, 170, 130, 65, 58, 234, 185,
228, 154, 164, 151, 126, 218, 122, 23, 102, 148,
161, 29, 61, 240, 222, 179, 11, 114, 167, 28,
239, 209, 83, 62, 143, 51, 38, 95, 236, 118,
42, 73, 129, 136, 238, 33, 196, 26, 235, 217,
197, 57, 153, 205, 173, 49, 139, 1, 24, 35,
221, 31, 78, 45, 249, 72, 79, 242, 101, 142,
120, 92, 88, 25, 141, 229, 152, 87, 103, 127,
5, 100, 175, 99, 182, 254, 245, 183, 60, 165,
206, 233, 104, 68, 224, 77, 67, 105, 41, 46,
172, 21, 89, 168, 10, 158, 110, 71, 223, 52,
53, 106, 207, 220, 34, 201, 192, 155, 137, 212,
237, 171, 18, 162, 13, 82, 187, 2, 47, 169,
215, 97, 30, 180, 80, 4, 246, 194, 22, 37,
134, 86, 85, 9, 190, 145
}
};
private bool encrypting;
private int[] gMDS0 = new int[256];
private int[] gMDS1 = new int[256];
private int[] gMDS2 = new int[256];
private int[] gMDS3 = new int[256];
private int[] gSubKeys;
private int[] gSBox;
private int k64Cnt;
private byte[] workingKey;
public string AlgorithmName => "Twofish";
public bool IsPartialBlockOkay => false;
public TwofishEngine()
{
int[] array = new int[2];
int[] array2 = new int[2];
int[] array3 = new int[2];
for (int i = 0; i < 256; i++)
{
int x = (array[0] = P[0, i] & 0xFF);
array2[0] = Mx_X(x) & 0xFF;
array3[0] = Mx_Y(x) & 0xFF;
x = (array[1] = P[1, i] & 0xFF);
array2[1] = Mx_X(x) & 0xFF;
array3[1] = Mx_Y(x) & 0xFF;
gMDS0[i] = array[1] | (array2[1] << 8) | (array3[1] << 16) | (array3[1] << 24);
gMDS1[i] = array3[0] | (array3[0] << 8) | (array2[0] << 16) | (array[0] << 24);
gMDS2[i] = array2[1] | (array3[1] << 8) | (array[1] << 16) | (array3[1] << 24);
gMDS3[i] = array2[0] | (array[0] << 8) | (array3[0] << 16) | (array2[0] << 24);
}
}
public void Init(bool forEncryption, ICipherParameters parameters)
{
if (!(parameters is KeyParameter))
{
throw new ArgumentException("invalid parameter passed to Twofish init - " + Platform.GetTypeName(parameters));
}
encrypting = forEncryption;
workingKey = ((KeyParameter)parameters).GetKey();
k64Cnt = workingKey.Length / 8;
SetKey(workingKey);
}
public int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
{
if (workingKey == null)
{
throw new InvalidOperationException("Twofish not initialised");
}
Check.DataLength(input, inOff, 16, "input buffer too short");
Check.OutputLength(output, outOff, 16, "output buffer too short");
if (encrypting)
{
EncryptBlock(input, inOff, output, outOff);
}
else
{
DecryptBlock(input, inOff, output, outOff);
}
return 16;
}
public void Reset()
{
if (workingKey != null)
{
SetKey(workingKey);
}
}
public int GetBlockSize()
{
return 16;
}
private void SetKey(byte[] key)
{
int[] array = new int[4];
int[] array2 = new int[4];
int[] array3 = new int[4];
gSubKeys = new int[40];
if (k64Cnt < 1)
{
throw new ArgumentException("Key size less than 64 bits");
}
if (k64Cnt > 4)
{
throw new ArgumentException("Key size larger than 256 bits");
}
int i = 0;
int num = 0;
for (; i < k64Cnt; i++)
{
num = i * 8;
array[i] = BytesTo32Bits(key, num);
array2[i] = BytesTo32Bits(key, num + 4);
array3[k64Cnt - 1 - i] = RS_MDS_Encode(array[i], array2[i]);
}
for (int j = 0; j < 20; j++)
{
int num2 = j * 33686018;
int num3 = F32(num2, array);
int num4 = F32(num2 + 16843009, array2);
num4 = (num4 << 8) | (num4 >>> 24);
num3 += num4;
gSubKeys[j * 2] = num3;
num3 += num4;
gSubKeys[j * 2 + 1] = (num3 << 9) | (num3 >>> 23);
}
int x = array3[0];
int x2 = array3[1];
int x3 = array3[2];
int x4 = array3[3];
gSBox = new int[1024];
for (int k = 0; k < 256; k++)
{
int num6;
int num7;
int num8;
int num5 = (num6 = (num7 = (num8 = k)));
switch (k64Cnt & 3)
{
case 1:
gSBox[k * 2] = gMDS0[(P[0, num5] & 0xFF) ^ M_b0(x)];
gSBox[k * 2 + 1] = gMDS1[(P[0, num6] & 0xFF) ^ M_b1(x)];
gSBox[k * 2 + 512] = gMDS2[(P[1, num7] & 0xFF) ^ M_b2(x)];
gSBox[k * 2 + 513] = gMDS3[(P[1, num8] & 0xFF) ^ M_b3(x)];
continue;
case 0:
num5 = (P[1, num5] & 0xFF) ^ M_b0(x4);
num6 = (P[0, num6] & 0xFF) ^ M_b1(x4);
num7 = (P[0, num7] & 0xFF) ^ M_b2(x4);
num8 = (P[1, num8] & 0xFF) ^ M_b3(x4);
goto case 3;
case 3:
num5 = (P[1, num5] & 0xFF) ^ M_b0(x3);
num6 = (P[1, num6] & 0xFF) ^ M_b1(x3);
num7 = (P[0, num7] & 0xFF) ^ M_b2(x3);
num8 = (P[0, num8] & 0xFF) ^ M_b3(x3);
break;
case 2:
break;
default:
continue;
}
gSBox[k * 2] = gMDS0[(P[0, (P[0, num5] & 0xFF) ^ M_b0(x2)] & 0xFF) ^ M_b0(x)];
gSBox[k * 2 + 1] = gMDS1[(P[0, (P[1, num6] & 0xFF) ^ M_b1(x2)] & 0xFF) ^ M_b1(x)];
gSBox[k * 2 + 512] = gMDS2[(P[1, (P[0, num7] & 0xFF) ^ M_b2(x2)] & 0xFF) ^ M_b2(x)];
gSBox[k * 2 + 513] = gMDS3[(P[1, (P[1, num8] & 0xFF) ^ M_b3(x2)] & 0xFF) ^ M_b3(x)];
}
}
private void EncryptBlock(byte[] src, int srcIndex, byte[] dst, int dstIndex)
{
int num = BytesTo32Bits(src, srcIndex) ^ gSubKeys[0];
int num2 = BytesTo32Bits(src, srcIndex + 4) ^ gSubKeys[1];
int num3 = BytesTo32Bits(src, srcIndex + 8) ^ gSubKeys[2];
int num4 = BytesTo32Bits(src, srcIndex + 12) ^ gSubKeys[3];
int num5 = 8;
for (int i = 0; i < 16; i += 2)
{
int num6 = Fe32_0(num);
int num7 = Fe32_3(num2);
num3 ^= num6 + num7 + gSubKeys[num5++];
num3 = (num3 >>> 1) | (num3 << 31);
num4 = ((num4 << 1) | (num4 >>> 31)) ^ (num6 + 2 * num7 + gSubKeys[num5++]);
num6 = Fe32_0(num3);
num7 = Fe32_3(num4);
num ^= num6 + num7 + gSubKeys[num5++];
num = (num >>> 1) | (num << 31);
num2 = ((num2 << 1) | (num2 >>> 31)) ^ (num6 + 2 * num7 + gSubKeys[num5++]);
}
Bits32ToBytes(num3 ^ gSubKeys[4], dst, dstIndex);
Bits32ToBytes(num4 ^ gSubKeys[5], dst, dstIndex + 4);
Bits32ToBytes(num ^ gSubKeys[6], dst, dstIndex + 8);
Bits32ToBytes(num2 ^ gSubKeys[7], dst, dstIndex + 12);
}
private void DecryptBlock(byte[] src, int srcIndex, byte[] dst, int dstIndex)
{
int num = BytesTo32Bits(src, srcIndex) ^ gSubKeys[4];
int num2 = BytesTo32Bits(src, srcIndex + 4) ^ gSubKeys[5];
int num3 = BytesTo32Bits(src, srcIndex + 8) ^ gSubKeys[6];
int num4 = BytesTo32Bits(src, srcIndex + 12) ^ gSubKeys[7];
int num5 = 39;
for (int i = 0; i < 16; i += 2)
{
int num6 = Fe32_0(num);
int num7 = Fe32_3(num2);
num4 ^= num6 + 2 * num7 + gSubKeys[num5--];
num3 = ((num3 << 1) | (num3 >>> 31)) ^ (num6 + num7 + gSubKeys[num5--]);
num4 = (num4 >>> 1) | (num4 << 31);
num6 = Fe32_0(num3);
num7 = Fe32_3(num4);
num2 ^= num6 + 2 * num7 + gSubKeys[num5--];
num = ((num << 1) | (num >>> 31)) ^ (num6 + num7 + gSubKeys[num5--]);
num2 = (num2 >>> 1) | (num2 << 31);
}
Bits32ToBytes(num3 ^ gSubKeys[0], dst, dstIndex);
Bits32ToBytes(num4 ^ gSubKeys[1], dst, dstIndex + 4);
Bits32ToBytes(num ^ gSubKeys[2], dst, dstIndex + 8);
Bits32ToBytes(num2 ^ gSubKeys[3], dst, dstIndex + 12);
}
private int F32(int x, int[] k32)
{
int num = M_b0(x);
int num2 = M_b1(x);
int num3 = M_b2(x);
int num4 = M_b3(x);
int x2 = k32[0];
int x3 = k32[1];
int x4 = k32[2];
int x5 = k32[3];
int result = 0;
switch (k64Cnt & 3)
{
case 1:
result = gMDS0[(P[0, num] & 0xFF) ^ M_b0(x2)] ^ gMDS1[(P[0, num2] & 0xFF) ^ M_b1(x2)] ^ gMDS2[(P[1, num3] & 0xFF) ^ M_b2(x2)] ^ gMDS3[(P[1, num4] & 0xFF) ^ M_b3(x2)];
break;
case 0:
num = (P[1, num] & 0xFF) ^ M_b0(x5);
num2 = (P[0, num2] & 0xFF) ^ M_b1(x5);
num3 = (P[0, num3] & 0xFF) ^ M_b2(x5);
num4 = (P[1, num4] & 0xFF) ^ M_b3(x5);
goto case 3;
case 3:
num = (P[1, num] & 0xFF) ^ M_b0(x4);
num2 = (P[1, num2] & 0xFF) ^ M_b1(x4);
num3 = (P[0, num3] & 0xFF) ^ M_b2(x4);
num4 = (P[0, num4] & 0xFF) ^ M_b3(x4);
goto case 2;
case 2:
result = gMDS0[(P[0, (P[0, num] & 0xFF) ^ M_b0(x3)] & 0xFF) ^ M_b0(x2)] ^ gMDS1[(P[0, (P[1, num2] & 0xFF) ^ M_b1(x3)] & 0xFF) ^ M_b1(x2)] ^ gMDS2[(P[1, (P[0, num3] & 0xFF) ^ M_b2(x3)] & 0xFF) ^ M_b2(x2)] ^ gMDS3[(P[1, (P[1, num4] & 0xFF) ^ M_b3(x3)] & 0xFF) ^ M_b3(x2)];
break;
}
return result;
}
private int RS_MDS_Encode(int k0, int k1)
{
int num = k1;
for (int i = 0; i < 4; i++)
{
num = RS_rem(num);
}
num ^= k0;
for (int j = 0; j < 4; j++)
{
num = RS_rem(num);
}
return num;
}
private int RS_rem(int x)
{
int num = (x >>> 24) & 0xFF;
int num2 = ((num << 1) ^ (((num & 0x80) != 0) ? 333 : 0)) & 0xFF;
int num3 = (num >>> 1) ^ (((num & 1) != 0) ? 166 : 0) ^ num2;
return (x << 8) ^ (num3 << 24) ^ (num2 << 16) ^ (num3 << 8) ^ num;
}
private int LFSR1(int x)
{
return (x >> 1) ^ (((x & 1) != 0) ? 180 : 0);
}
private int LFSR2(int x)
{
return (x >> 2) ^ (((x & 2) != 0) ? 180 : 0) ^ (((x & 1) != 0) ? 90 : 0);
}
private int Mx_X(int x)
{
return x ^ LFSR2(x);
}
private int Mx_Y(int x)
{
return x ^ LFSR1(x) ^ LFSR2(x);
}
private int M_b0(int x)
{
return x & 0xFF;
}
private int M_b1(int x)
{
return (x >>> 8) & 0xFF;
}
private int M_b2(int x)
{
return (x >>> 16) & 0xFF;
}
private int M_b3(int x)
{
return (x >>> 24) & 0xFF;
}
private int Fe32_0(int x)
{
return gSBox[2 * (x & 0xFF)] ^ gSBox[1 + 2 * ((x >>> 8) & 0xFF)] ^ gSBox[512 + 2 * ((x >>> 16) & 0xFF)] ^ gSBox[513 + 2 * ((x >>> 24) & 0xFF)];
}
private int Fe32_3(int x)
{
return gSBox[2 * ((x >>> 24) & 0xFF)] ^ gSBox[1 + 2 * (x & 0xFF)] ^ gSBox[512 + 2 * ((x >>> 8) & 0xFF)] ^ gSBox[513 + 2 * ((x >>> 16) & 0xFF)];
}
private int BytesTo32Bits(byte[] b, int p)
{
return (b[p] & 0xFF) | ((b[p + 1] & 0xFF) << 8) | ((b[p + 2] & 0xFF) << 16) | ((b[p + 3] & 0xFF) << 24);
}
private void Bits32ToBytes(int inData, byte[] b, int offset)
{
b[offset] = (byte)inData;
b[offset + 1] = (byte)(inData >> 8);
b[offset + 2] = (byte)(inData >> 16);
b[offset + 3] = (byte)(inData >> 24);
}
}