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

1061 lines
30 KiB
C#

using System;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Utilities;
namespace Org.BouncyCastle.Crypto.Engines;
public class Dstu7624Engine : IBlockCipher
{
private const int ROUNDS_128 = 10;
private const int ROUNDS_256 = 14;
private const int ROUNDS_512 = 18;
private const ulong mdsMatrix = 290207332435296513uL;
private const ulong mdsInvMatrix = 14616231584692868525uL;
private ulong[] internalState;
private ulong[] workingKey;
private ulong[][] roundKeys;
private int wordsInBlock;
private int wordsInKey;
private int roundsAmount;
private bool forEncryption;
private static readonly byte[] S0 = new byte[256]
{
168, 67, 95, 6, 107, 117, 108, 89, 113, 223,
135, 149, 23, 240, 216, 9, 109, 243, 29, 203,
201, 77, 44, 175, 121, 224, 151, 253, 111, 75,
69, 57, 62, 221, 163, 79, 180, 182, 154, 14,
31, 191, 21, 225, 73, 210, 147, 198, 146, 114,
158, 97, 209, 99, 250, 238, 244, 25, 213, 173,
88, 164, 187, 161, 220, 242, 131, 55, 66, 228,
122, 50, 156, 204, 171, 74, 143, 110, 4, 39,
46, 231, 226, 90, 150, 22, 35, 43, 194, 101,
102, 15, 188, 169, 71, 65, 52, 72, 252, 183,
106, 136, 165, 83, 134, 249, 91, 219, 56, 123,
195, 30, 34, 51, 36, 40, 54, 199, 178, 59,
142, 119, 186, 245, 20, 159, 8, 85, 155, 76,
254, 96, 92, 218, 24, 70, 205, 125, 33, 176,
63, 27, 137, 255, 235, 132, 105, 58, 157, 215,
211, 112, 103, 64, 181, 222, 93, 48, 145, 177,
120, 17, 1, 229, 0, 104, 152, 160, 197, 2,
166, 116, 45, 11, 162, 118, 179, 190, 206, 189,
174, 233, 138, 49, 28, 236, 241, 153, 148, 170,
246, 38, 47, 239, 232, 140, 53, 3, 212, 127,
251, 5, 193, 94, 144, 32, 61, 130, 247, 234,
10, 13, 126, 248, 80, 26, 196, 7, 87, 184,
60, 98, 227, 200, 172, 82, 100, 16, 208, 217,
19, 12, 18, 41, 81, 185, 207, 214, 115, 141,
129, 84, 192, 237, 78, 68, 167, 42, 133, 37,
230, 202, 124, 139, 86, 128
};
private static readonly byte[] S1 = new byte[256]
{
206, 187, 235, 146, 234, 203, 19, 193, 233, 58,
214, 178, 210, 144, 23, 248, 66, 21, 86, 180,
101, 28, 136, 67, 197, 92, 54, 186, 245, 87,
103, 141, 49, 246, 100, 88, 158, 244, 34, 170,
117, 15, 2, 177, 223, 109, 115, 77, 124, 38,
46, 247, 8, 93, 68, 62, 159, 20, 200, 174,
84, 16, 216, 188, 26, 107, 105, 243, 189, 51,
171, 250, 209, 155, 104, 78, 22, 149, 145, 238,
76, 99, 142, 91, 204, 60, 25, 161, 129, 73,
123, 217, 111, 55, 96, 202, 231, 43, 72, 253,
150, 69, 252, 65, 18, 13, 121, 229, 137, 140,
227, 32, 48, 220, 183, 108, 74, 181, 63, 151,
212, 98, 45, 6, 164, 165, 131, 95, 42, 218,
201, 0, 126, 162, 85, 191, 17, 213, 156, 207,
14, 10, 61, 81, 125, 147, 27, 254, 196, 71,
9, 134, 11, 143, 157, 106, 7, 185, 176, 152,
24, 50, 113, 75, 239, 59, 112, 160, 228, 64,
255, 195, 169, 230, 120, 249, 139, 70, 128, 30,
56, 225, 184, 168, 224, 12, 35, 118, 29, 37,
36, 5, 241, 110, 148, 40, 154, 132, 232, 163,
79, 119, 211, 133, 226, 82, 242, 130, 80, 122,
47, 116, 83, 179, 97, 175, 57, 53, 222, 205,
31, 153, 172, 173, 114, 44, 221, 208, 135, 190,
94, 166, 236, 4, 198, 3, 52, 251, 219, 89,
182, 194, 1, 240, 90, 237, 167, 102, 33, 127,
138, 39, 199, 192, 41, 215
};
private static readonly byte[] S2 = new byte[256]
{
147, 217, 154, 181, 152, 34, 69, 252, 186, 106,
223, 2, 159, 220, 81, 89, 74, 23, 43, 194,
148, 244, 187, 163, 98, 228, 113, 212, 205, 112,
22, 225, 73, 60, 192, 216, 92, 155, 173, 133,
83, 161, 122, 200, 45, 224, 209, 114, 166, 44,
196, 227, 118, 120, 183, 180, 9, 59, 14, 65,
76, 222, 178, 144, 37, 165, 215, 3, 17, 0,
195, 46, 146, 239, 78, 18, 157, 125, 203, 53,
16, 213, 79, 158, 77, 169, 85, 198, 208, 123,
24, 151, 211, 54, 230, 72, 86, 129, 143, 119,
204, 156, 185, 226, 172, 184, 47, 21, 164, 124,
218, 56, 30, 11, 5, 214, 20, 110, 108, 126,
102, 253, 177, 229, 96, 175, 94, 51, 135, 201,
240, 93, 109, 63, 136, 141, 199, 247, 29, 233,
236, 237, 128, 41, 39, 207, 153, 168, 80, 15,
55, 36, 40, 48, 149, 210, 62, 91, 64, 131,
179, 105, 87, 31, 7, 28, 138, 188, 32, 235,
206, 142, 171, 238, 49, 162, 115, 249, 202, 58,
26, 251, 13, 193, 254, 250, 242, 111, 189, 150,
221, 67, 82, 182, 8, 243, 174, 190, 25, 137,
50, 38, 176, 234, 75, 100, 132, 130, 107, 245,
121, 191, 1, 95, 117, 99, 27, 35, 61, 104,
42, 101, 232, 145, 246, 255, 19, 88, 241, 71,
10, 127, 197, 167, 231, 97, 90, 6, 70, 68,
66, 4, 160, 219, 57, 134, 84, 170, 140, 52,
33, 139, 248, 12, 116, 103
};
private static readonly byte[] S3 = new byte[256]
{
104, 141, 202, 77, 115, 75, 78, 42, 212, 82,
38, 179, 84, 30, 25, 31, 34, 3, 70, 61,
45, 74, 83, 131, 19, 138, 183, 213, 37, 121,
245, 189, 88, 47, 13, 2, 237, 81, 158, 17,
242, 62, 85, 94, 209, 22, 60, 102, 112, 93,
243, 69, 64, 204, 232, 148, 86, 8, 206, 26,
58, 210, 225, 223, 181, 56, 110, 14, 229, 244,
249, 134, 233, 79, 214, 133, 35, 207, 50, 153,
49, 20, 174, 238, 200, 72, 211, 48, 161, 146,
65, 177, 24, 196, 44, 113, 114, 68, 21, 253,
55, 190, 95, 170, 155, 136, 216, 171, 137, 156,
250, 96, 234, 188, 98, 12, 36, 166, 168, 236,
103, 32, 219, 124, 40, 221, 172, 91, 52, 126,
16, 241, 123, 143, 99, 160, 5, 154, 67, 119,
33, 191, 39, 9, 195, 159, 182, 215, 41, 194,
235, 192, 164, 139, 140, 29, 251, 255, 193, 178,
151, 46, 248, 101, 246, 117, 7, 4, 73, 51,
228, 217, 185, 208, 66, 199, 108, 144, 0, 142,
111, 80, 1, 197, 218, 71, 63, 205, 105, 162,
226, 122, 167, 198, 147, 15, 10, 6, 230, 43,
150, 163, 28, 175, 106, 18, 132, 57, 231, 176,
130, 247, 254, 157, 135, 92, 129, 53, 222, 180,
165, 252, 128, 239, 203, 187, 107, 118, 186, 90,
125, 120, 11, 149, 227, 173, 116, 152, 59, 54,
100, 109, 220, 240, 89, 169, 76, 23, 127, 145,
184, 201, 87, 27, 224, 97
};
private static readonly byte[] T0 = new byte[256]
{
164, 162, 169, 197, 78, 201, 3, 217, 126, 15,
210, 173, 231, 211, 39, 91, 227, 161, 232, 230,
124, 42, 85, 12, 134, 57, 215, 141, 184, 18,
111, 40, 205, 138, 112, 86, 114, 249, 191, 79,
115, 233, 247, 87, 22, 172, 80, 192, 157, 183,
71, 113, 96, 196, 116, 67, 108, 31, 147, 119,
220, 206, 32, 140, 153, 95, 68, 1, 245, 30,
135, 94, 97, 44, 75, 29, 129, 21, 244, 35,
214, 234, 225, 103, 241, 127, 254, 218, 60, 7,
83, 106, 132, 156, 203, 2, 131, 51, 221, 53,
226, 89, 90, 152, 165, 146, 100, 4, 6, 16,
77, 28, 151, 8, 49, 238, 171, 5, 175, 121,
160, 24, 70, 109, 252, 137, 212, 199, 255, 240,
207, 66, 145, 248, 104, 10, 101, 142, 182, 253,
195, 239, 120, 76, 204, 158, 48, 46, 188, 11,
84, 26, 166, 187, 38, 128, 72, 148, 50, 125,
167, 63, 174, 34, 61, 102, 170, 246, 0, 93,
189, 74, 224, 59, 180, 23, 139, 159, 118, 176,
36, 154, 37, 99, 219, 235, 122, 62, 92, 179,
177, 41, 242, 202, 88, 110, 216, 168, 47, 117,
223, 20, 251, 19, 73, 136, 178, 236, 228, 52,
45, 150, 198, 58, 237, 149, 14, 229, 133, 107,
64, 33, 155, 9, 25, 43, 82, 222, 69, 163,
250, 81, 194, 181, 209, 144, 185, 243, 55, 193,
13, 186, 65, 17, 56, 123, 190, 208, 213, 105,
54, 200, 98, 27, 130, 143
};
private static readonly byte[] T1 = new byte[256]
{
131, 242, 42, 235, 233, 191, 123, 156, 52, 150,
141, 152, 185, 105, 140, 41, 61, 136, 104, 6,
57, 17, 76, 14, 160, 86, 64, 146, 21, 188,
179, 220, 111, 248, 38, 186, 190, 189, 49, 251,
195, 254, 128, 97, 225, 122, 50, 210, 112, 32,
161, 69, 236, 217, 26, 93, 180, 216, 9, 165,
85, 142, 55, 118, 169, 103, 16, 23, 54, 101,
177, 149, 98, 89, 116, 163, 80, 47, 75, 200,
208, 143, 205, 212, 60, 134, 18, 29, 35, 239,
244, 83, 25, 53, 230, 127, 94, 214, 121, 81,
34, 20, 247, 30, 74, 66, 155, 65, 115, 45,
193, 92, 166, 162, 224, 46, 211, 40, 187, 201,
174, 106, 209, 90, 48, 144, 132, 249, 178, 88,
207, 126, 197, 203, 151, 228, 22, 108, 250, 176,
109, 31, 82, 153, 13, 78, 3, 145, 194, 77,
100, 119, 159, 221, 196, 73, 138, 154, 36, 56,
167, 87, 133, 199, 124, 125, 231, 246, 183, 172,
39, 70, 222, 223, 59, 215, 158, 43, 11, 213,
19, 117, 240, 114, 182, 157, 27, 1, 63, 68,
229, 135, 253, 7, 241, 171, 148, 24, 234, 252,
58, 130, 95, 5, 84, 219, 0, 139, 227, 72,
12, 202, 120, 137, 10, 255, 62, 91, 129, 238,
113, 226, 218, 44, 184, 181, 204, 110, 168, 107,
173, 96, 198, 8, 4, 2, 232, 245, 79, 164,
243, 192, 206, 67, 37, 28, 33, 51, 15, 175,
71, 237, 102, 99, 147, 170
};
private static readonly byte[] T2 = new byte[256]
{
69, 212, 11, 67, 241, 114, 237, 164, 194, 56,
230, 113, 253, 182, 58, 149, 80, 68, 75, 226,
116, 107, 30, 17, 90, 198, 180, 216, 165, 138,
112, 163, 168, 250, 5, 217, 151, 64, 201, 144,
152, 143, 220, 18, 49, 44, 71, 106, 153, 174,
200, 127, 249, 79, 93, 150, 111, 244, 179, 57,
33, 218, 156, 133, 158, 59, 240, 191, 239, 6,
238, 229, 95, 32, 16, 204, 60, 84, 74, 82,
148, 14, 192, 40, 246, 86, 96, 162, 227, 15,
236, 157, 36, 131, 126, 213, 124, 235, 24, 215,
205, 221, 120, 255, 219, 161, 9, 208, 118, 132,
117, 187, 29, 26, 47, 176, 254, 214, 52, 99,
53, 210, 42, 89, 109, 77, 119, 231, 142, 97,
207, 159, 206, 39, 245, 128, 134, 199, 166, 251,
248, 135, 171, 98, 63, 223, 72, 0, 20, 154,
189, 91, 4, 146, 2, 37, 101, 76, 83, 12,
242, 41, 175, 23, 108, 65, 48, 233, 147, 85,
247, 172, 104, 38, 196, 125, 202, 122, 62, 160,
55, 3, 193, 54, 105, 102, 8, 22, 167, 188,
197, 211, 34, 183, 19, 70, 50, 232, 87, 136,
43, 129, 178, 78, 100, 28, 170, 145, 88, 46,
155, 92, 27, 81, 115, 66, 35, 1, 110, 243,
13, 190, 61, 10, 45, 31, 103, 51, 25, 123,
94, 234, 222, 139, 203, 169, 140, 141, 173, 73,
130, 228, 186, 195, 21, 209, 224, 137, 252, 177,
185, 181, 7, 121, 184, 225
};
private static readonly byte[] T3 = new byte[256]
{
178, 182, 35, 17, 167, 136, 197, 166, 57, 143,
196, 232, 115, 34, 67, 195, 130, 39, 205, 24,
81, 98, 45, 247, 92, 14, 59, 253, 202, 155,
13, 15, 121, 140, 16, 76, 116, 28, 10, 142,
124, 148, 7, 199, 94, 20, 161, 33, 87, 80,
78, 169, 128, 217, 239, 100, 65, 207, 60, 238,
46, 19, 41, 186, 52, 90, 174, 138, 97, 51,
18, 185, 85, 168, 21, 5, 246, 3, 6, 73,
181, 37, 9, 22, 12, 42, 56, 252, 32, 244,
229, 127, 215, 49, 43, 102, 111, 255, 114, 134,
240, 163, 47, 120, 0, 188, 204, 226, 176, 241,
66, 180, 48, 95, 96, 4, 236, 165, 227, 139,
231, 29, 191, 132, 123, 230, 129, 248, 222, 216,
210, 23, 206, 75, 71, 214, 105, 108, 25, 153,
154, 1, 179, 133, 177, 249, 89, 194, 55, 233,
200, 160, 237, 79, 137, 104, 109, 213, 38, 145,
135, 88, 189, 201, 152, 220, 117, 192, 118, 245,
103, 107, 126, 235, 82, 203, 209, 91, 159, 11,
219, 64, 146, 26, 250, 172, 228, 225, 113, 31,
101, 141, 151, 158, 149, 144, 93, 183, 193, 175,
84, 251, 2, 224, 53, 187, 58, 77, 173, 44,
61, 86, 8, 27, 74, 147, 106, 171, 184, 122,
242, 125, 218, 63, 254, 62, 190, 234, 170, 68,
198, 208, 54, 72, 112, 150, 119, 36, 83, 223,
243, 131, 40, 50, 69, 30, 164, 211, 162, 70,
110, 156, 221, 99, 212, 157
};
public virtual string AlgorithmName => "DSTU7624";
public virtual bool IsPartialBlockOkay => false;
public Dstu7624Engine(int blockSizeBits)
{
if (blockSizeBits != 128 && blockSizeBits != 256 && blockSizeBits != 512)
{
throw new ArgumentException("unsupported block length: only 128/256/512 are allowed");
}
wordsInBlock = blockSizeBits / 64;
internalState = new ulong[wordsInBlock];
}
public virtual void Init(bool forEncryption, ICipherParameters parameters)
{
if (!(parameters is KeyParameter))
{
throw new ArgumentException("Invalid parameter passed to Dstu7624Engine Init");
}
this.forEncryption = forEncryption;
byte[] key = ((KeyParameter)parameters).GetKey();
int num = key.Length << 3;
int num2 = wordsInBlock << 6;
if (num != 128 && num != 256 && num != 512)
{
throw new ArgumentException("unsupported key length: only 128/256/512 are allowed");
}
if (num != num2 && num != 2 * num2)
{
throw new ArgumentException("Unsupported key length");
}
switch (num)
{
case 128:
roundsAmount = 10;
break;
case 256:
roundsAmount = 14;
break;
case 512:
roundsAmount = 18;
break;
}
wordsInKey = num / 64;
roundKeys = new ulong[roundsAmount + 1][];
for (int i = 0; i < roundKeys.Length; i++)
{
roundKeys[i] = new ulong[wordsInBlock];
}
workingKey = new ulong[wordsInKey];
if (key.Length != wordsInKey * 8)
{
throw new ArgumentException("Invalid key parameter passed to Dstu7624Engine Init");
}
Pack.LE_To_UInt64(key, 0, workingKey);
ulong[] array = new ulong[wordsInBlock];
WorkingKeyExpandKT(workingKey, array);
WorkingKeyExpandEven(workingKey, array);
WorkingKeyExpandOdd();
}
private void WorkingKeyExpandKT(ulong[] workingKey, ulong[] tempKeys)
{
ulong[] array = new ulong[wordsInBlock];
ulong[] array2 = new ulong[wordsInBlock];
internalState = new ulong[wordsInBlock];
ulong[] array3;
(array3 = internalState)[0] = array3[0] + (ulong)(wordsInBlock + wordsInKey + 1);
if (wordsInBlock == wordsInKey)
{
Array.Copy(workingKey, 0, array, 0, array.Length);
Array.Copy(workingKey, 0, array2, 0, array2.Length);
}
else
{
Array.Copy(workingKey, 0, array, 0, wordsInBlock);
Array.Copy(workingKey, wordsInBlock, array2, 0, wordsInBlock);
}
for (int i = 0; i < internalState.Length; i++)
{
ulong[] array4 = (array3 = internalState);
int num = i;
nint num2 = num;
array4[num] = array3[num2] + array[i];
}
EncryptionRound();
for (int j = 0; j < internalState.Length; j++)
{
ulong[] array5 = (array3 = internalState);
int num3 = j;
nint num2 = num3;
array5[num3] = array3[num2] ^ array2[j];
}
EncryptionRound();
for (int k = 0; k < internalState.Length; k++)
{
ulong[] array6 = (array3 = internalState);
int num4 = k;
nint num2 = num4;
array6[num4] = array3[num2] + array[k];
}
EncryptionRound();
Array.Copy(internalState, 0, tempKeys, 0, wordsInBlock);
}
private void WorkingKeyExpandEven(ulong[] workingKey, ulong[] tempKey)
{
ulong[] array = new ulong[wordsInKey];
ulong[] array2 = new ulong[wordsInBlock];
int num = 0;
Array.Copy(workingKey, 0, array, 0, wordsInKey);
ulong num2 = 281479271743489uL;
while (true)
{
for (int i = 0; i < wordsInBlock; i++)
{
array2[i] = tempKey[i] + num2;
}
for (int j = 0; j < wordsInBlock; j++)
{
internalState[j] = array[j] + array2[j];
}
EncryptionRound();
for (int k = 0; k < wordsInBlock; k++)
{
ulong[] array4;
ulong[] array3 = (array4 = internalState);
int num3 = k;
nint num4 = num3;
array3[num3] = array4[num4] ^ array2[k];
}
EncryptionRound();
for (int l = 0; l < wordsInBlock; l++)
{
ulong[] array4;
ulong[] array5 = (array4 = internalState);
int num5 = l;
nint num4 = num5;
array5[num5] = array4[num4] + array2[l];
}
Array.Copy(internalState, 0, roundKeys[num], 0, wordsInBlock);
if (roundsAmount == num)
{
break;
}
if (wordsInKey != wordsInBlock)
{
num += 2;
num2 <<= 1;
for (int m = 0; m < wordsInBlock; m++)
{
array2[m] = tempKey[m] + num2;
}
for (int n = 0; n < wordsInBlock; n++)
{
internalState[n] = array[wordsInBlock + n] + array2[n];
}
EncryptionRound();
for (int num6 = 0; num6 < wordsInBlock; num6++)
{
ulong[] array4;
ulong[] array6 = (array4 = internalState);
int num7 = num6;
nint num4 = num7;
array6[num7] = array4[num4] ^ array2[num6];
}
EncryptionRound();
for (int num8 = 0; num8 < wordsInBlock; num8++)
{
ulong[] array4;
ulong[] array7 = (array4 = internalState);
int num9 = num8;
nint num4 = num9;
array7[num9] = array4[num4] + array2[num8];
}
Array.Copy(internalState, 0, roundKeys[num], 0, wordsInBlock);
if (roundsAmount == num)
{
break;
}
}
num += 2;
num2 <<= 1;
ulong num10 = array[0];
for (int num11 = 1; num11 < array.Length; num11++)
{
array[num11 - 1] = array[num11];
}
array[^1] = num10;
}
}
private void WorkingKeyExpandOdd()
{
for (int i = 1; i < roundsAmount; i += 2)
{
RotateLeft(roundKeys[i - 1], roundKeys[i]);
}
}
public virtual int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
{
if (workingKey == null)
{
throw new InvalidOperationException("Dstu7624Engine not initialised");
}
Check.DataLength(input, inOff, GetBlockSize(), "input buffer too short");
Check.OutputLength(output, outOff, GetBlockSize(), "output buffer too short");
if (forEncryption)
{
int num = wordsInBlock;
if (num == 2)
{
EncryptBlock_128(input, inOff, output, outOff);
}
else
{
Pack.LE_To_UInt64(input, inOff, internalState);
AddRoundKey(0);
int num2 = 0;
while (true)
{
EncryptionRound();
if (++num2 == roundsAmount)
{
break;
}
XorRoundKey(num2);
}
AddRoundKey(roundsAmount);
Pack.UInt64_To_LE(internalState, output, outOff);
}
}
else
{
int num = wordsInBlock;
if (num == 2)
{
DecryptBlock_128(input, inOff, output, outOff);
}
else
{
Pack.LE_To_UInt64(input, inOff, internalState);
SubRoundKey(roundsAmount);
int num3 = roundsAmount;
while (true)
{
DecryptionRound();
if (--num3 == 0)
{
break;
}
XorRoundKey(num3);
}
SubRoundKey(0);
Pack.UInt64_To_LE(internalState, output, outOff);
}
}
return GetBlockSize();
}
private void EncryptionRound()
{
SubBytes();
ShiftRows();
MixColumns();
}
private void DecryptionRound()
{
MixColumnsInv();
InvShiftRows();
InvSubBytes();
}
private void DecryptBlock_128(byte[] input, int inOff, byte[] output, int outOff)
{
ulong num = Pack.LE_To_UInt64(input, inOff);
ulong num2 = Pack.LE_To_UInt64(input, inOff + 8);
ulong[] array = roundKeys[roundsAmount];
num -= array[0];
num2 -= array[1];
int num3 = roundsAmount;
while (true)
{
num = MixColumnInv(num);
num2 = MixColumnInv(num2);
uint num4 = (uint)num;
uint num5 = (uint)(num >> 32);
uint num6 = (uint)num2;
uint num7 = (uint)(num2 >> 32);
byte b = T0[num4 & 0xFF];
byte b2 = T1[(num4 >> 8) & 0xFF];
byte b3 = T2[(num4 >> 16) & 0xFF];
byte b4 = T3[num4 >> 24];
num4 = (uint)(b | (b2 << 8) | (b3 << 16) | (b4 << 24));
byte b5 = T0[num7 & 0xFF];
byte b6 = T1[(num7 >> 8) & 0xFF];
byte b7 = T2[(num7 >> 16) & 0xFF];
byte b8 = T3[num7 >> 24];
num7 = (uint)(b5 | (b6 << 8) | (b7 << 16) | (b8 << 24));
num = num4 | ((ulong)num7 << 32);
byte b9 = T0[num6 & 0xFF];
byte b10 = T1[(num6 >> 8) & 0xFF];
byte b11 = T2[(num6 >> 16) & 0xFF];
byte b12 = T3[num6 >> 24];
num6 = (uint)(b9 | (b10 << 8) | (b11 << 16) | (b12 << 24));
byte b13 = T0[num5 & 0xFF];
byte b14 = T1[(num5 >> 8) & 0xFF];
byte b15 = T2[(num5 >> 16) & 0xFF];
byte b16 = T3[num5 >> 24];
num5 = (uint)(b13 | (b14 << 8) | (b15 << 16) | (b16 << 24));
num2 = num6 | ((ulong)num5 << 32);
if (--num3 == 0)
{
break;
}
array = roundKeys[num3];
num ^= array[0];
num2 ^= array[1];
}
array = roundKeys[0];
num -= array[0];
num2 -= array[1];
Pack.UInt64_To_LE(num, output, outOff);
Pack.UInt64_To_LE(num2, output, outOff + 8);
}
private void EncryptBlock_128(byte[] input, int inOff, byte[] output, int outOff)
{
ulong num = Pack.LE_To_UInt64(input, inOff);
ulong num2 = Pack.LE_To_UInt64(input, inOff + 8);
ulong[] array = roundKeys[0];
num += array[0];
num2 += array[1];
int num3 = 0;
while (true)
{
uint num4 = (uint)num;
uint num5 = (uint)(num >> 32);
uint num6 = (uint)num2;
uint num7 = (uint)(num2 >> 32);
byte b = S0[num4 & 0xFF];
byte b2 = S1[(num4 >> 8) & 0xFF];
byte b3 = S2[(num4 >> 16) & 0xFF];
byte b4 = S3[num4 >> 24];
num4 = (uint)(b | (b2 << 8) | (b3 << 16) | (b4 << 24));
byte b5 = S0[num7 & 0xFF];
byte b6 = S1[(num7 >> 8) & 0xFF];
byte b7 = S2[(num7 >> 16) & 0xFF];
byte b8 = S3[num7 >> 24];
num7 = (uint)(b5 | (b6 << 8) | (b7 << 16) | (b8 << 24));
num = num4 | ((ulong)num7 << 32);
byte b9 = S0[num6 & 0xFF];
byte b10 = S1[(num6 >> 8) & 0xFF];
byte b11 = S2[(num6 >> 16) & 0xFF];
byte b12 = S3[num6 >> 24];
num6 = (uint)(b9 | (b10 << 8) | (b11 << 16) | (b12 << 24));
byte b13 = S0[num5 & 0xFF];
byte b14 = S1[(num5 >> 8) & 0xFF];
byte b15 = S2[(num5 >> 16) & 0xFF];
byte b16 = S3[num5 >> 24];
num5 = (uint)(b13 | (b14 << 8) | (b15 << 16) | (b16 << 24));
num2 = num6 | ((ulong)num5 << 32);
num = MixColumn(num);
num2 = MixColumn(num2);
if (++num3 == roundsAmount)
{
break;
}
array = roundKeys[num3];
num ^= array[0];
num2 ^= array[1];
}
array = roundKeys[roundsAmount];
num += array[0];
num2 += array[1];
Pack.UInt64_To_LE(num, output, outOff);
Pack.UInt64_To_LE(num2, output, outOff + 8);
}
private void SubBytes()
{
for (int i = 0; i < wordsInBlock; i++)
{
ulong num = internalState[i];
uint num2 = (uint)num;
uint num3 = (uint)(num >> 32);
byte b = S0[num2 & 0xFF];
byte b2 = S1[(num2 >> 8) & 0xFF];
byte b3 = S2[(num2 >> 16) & 0xFF];
byte b4 = S3[num2 >> 24];
num2 = (uint)(b | (b2 << 8) | (b3 << 16) | (b4 << 24));
byte b5 = S0[num3 & 0xFF];
byte b6 = S1[(num3 >> 8) & 0xFF];
byte b7 = S2[(num3 >> 16) & 0xFF];
byte b8 = S3[num3 >> 24];
num3 = (uint)(b5 | (b6 << 8) | (b7 << 16) | (b8 << 24));
internalState[i] = num2 | ((ulong)num3 << 32);
}
}
private void InvSubBytes()
{
for (int i = 0; i < wordsInBlock; i++)
{
ulong num = internalState[i];
uint num2 = (uint)num;
uint num3 = (uint)(num >> 32);
byte b = T0[num2 & 0xFF];
byte b2 = T1[(num2 >> 8) & 0xFF];
byte b3 = T2[(num2 >> 16) & 0xFF];
byte b4 = T3[num2 >> 24];
num2 = (uint)(b | (b2 << 8) | (b3 << 16) | (b4 << 24));
byte b5 = T0[num3 & 0xFF];
byte b6 = T1[(num3 >> 8) & 0xFF];
byte b7 = T2[(num3 >> 16) & 0xFF];
byte b8 = T3[num3 >> 24];
num3 = (uint)(b5 | (b6 << 8) | (b7 << 16) | (b8 << 24));
internalState[i] = num2 | ((ulong)num3 << 32);
}
}
private void ShiftRows()
{
switch (wordsInBlock)
{
case 2:
{
ulong num15 = internalState[0];
ulong num16 = internalState[1];
ulong num17 = (num15 ^ num16) & 0xFFFFFFFF00000000uL;
num15 ^= num17;
num16 ^= num17;
internalState[0] = num15;
internalState[1] = num16;
break;
}
case 4:
{
ulong num10 = internalState[0];
ulong num11 = internalState[1];
ulong num12 = internalState[2];
ulong num13 = internalState[3];
ulong num14 = (num10 ^ num12) & 0xFFFFFFFF00000000uL;
num10 ^= num14;
num12 ^= num14;
num14 = (num11 ^ num13) & 0xFFFFFFFF0000L;
num11 ^= num14;
num13 ^= num14;
num14 = (num10 ^ num11) & 0xFFFF0000FFFF0000uL;
num10 ^= num14;
num11 ^= num14;
num14 = (num12 ^ num13) & 0xFFFF0000FFFF0000uL;
num12 ^= num14;
num13 ^= num14;
internalState[0] = num10;
internalState[1] = num11;
internalState[2] = num12;
internalState[3] = num13;
break;
}
case 8:
{
ulong num = internalState[0];
ulong num2 = internalState[1];
ulong num3 = internalState[2];
ulong num4 = internalState[3];
ulong num5 = internalState[4];
ulong num6 = internalState[5];
ulong num7 = internalState[6];
ulong num8 = internalState[7];
ulong num9 = (num ^ num5) & 0xFFFFFFFF00000000uL;
num ^= num9;
num5 ^= num9;
num9 = (num2 ^ num6) & 0xFFFFFFFF000000L;
num2 ^= num9;
num6 ^= num9;
num9 = (num3 ^ num7) & 0xFFFFFFFF0000L;
num3 ^= num9;
num7 ^= num9;
num9 = (num4 ^ num8) & 0xFFFFFFFF00L;
num4 ^= num9;
num8 ^= num9;
num9 = (num ^ num3) & 0xFFFF0000FFFF0000uL;
num ^= num9;
num3 ^= num9;
num9 = (num2 ^ num4) & 0xFFFF0000FFFF00L;
num2 ^= num9;
num4 ^= num9;
num9 = (num5 ^ num7) & 0xFFFF0000FFFF0000uL;
num5 ^= num9;
num7 ^= num9;
num9 = (num6 ^ num8) & 0xFFFF0000FFFF00L;
num6 ^= num9;
num8 ^= num9;
num9 = (num ^ num2) & 0xFF00FF00FF00FF00uL;
num ^= num9;
num2 ^= num9;
num9 = (num3 ^ num4) & 0xFF00FF00FF00FF00uL;
num3 ^= num9;
num4 ^= num9;
num9 = (num5 ^ num6) & 0xFF00FF00FF00FF00uL;
num5 ^= num9;
num6 ^= num9;
num9 = (num7 ^ num8) & 0xFF00FF00FF00FF00uL;
num7 ^= num9;
num8 ^= num9;
internalState[0] = num;
internalState[1] = num2;
internalState[2] = num3;
internalState[3] = num4;
internalState[4] = num5;
internalState[5] = num6;
internalState[6] = num7;
internalState[7] = num8;
break;
}
default:
throw new InvalidOperationException("unsupported block length: only 128/256/512 are allowed");
}
}
private void InvShiftRows()
{
switch (wordsInBlock)
{
case 2:
{
ulong num15 = internalState[0];
ulong num16 = internalState[1];
ulong num17 = (num15 ^ num16) & 0xFFFFFFFF00000000uL;
num15 ^= num17;
num16 ^= num17;
internalState[0] = num15;
internalState[1] = num16;
break;
}
case 4:
{
ulong num10 = internalState[0];
ulong num11 = internalState[1];
ulong num12 = internalState[2];
ulong num13 = internalState[3];
ulong num14 = (num10 ^ num11) & 0xFFFF0000FFFF0000uL;
num10 ^= num14;
num11 ^= num14;
num14 = (num12 ^ num13) & 0xFFFF0000FFFF0000uL;
num12 ^= num14;
num13 ^= num14;
num14 = (num10 ^ num12) & 0xFFFFFFFF00000000uL;
num10 ^= num14;
num12 ^= num14;
num14 = (num11 ^ num13) & 0xFFFFFFFF0000L;
num11 ^= num14;
num13 ^= num14;
internalState[0] = num10;
internalState[1] = num11;
internalState[2] = num12;
internalState[3] = num13;
break;
}
case 8:
{
ulong num = internalState[0];
ulong num2 = internalState[1];
ulong num3 = internalState[2];
ulong num4 = internalState[3];
ulong num5 = internalState[4];
ulong num6 = internalState[5];
ulong num7 = internalState[6];
ulong num8 = internalState[7];
ulong num9 = (num ^ num2) & 0xFF00FF00FF00FF00uL;
num ^= num9;
num2 ^= num9;
num9 = (num3 ^ num4) & 0xFF00FF00FF00FF00uL;
num3 ^= num9;
num4 ^= num9;
num9 = (num5 ^ num6) & 0xFF00FF00FF00FF00uL;
num5 ^= num9;
num6 ^= num9;
num9 = (num7 ^ num8) & 0xFF00FF00FF00FF00uL;
num7 ^= num9;
num8 ^= num9;
num9 = (num ^ num3) & 0xFFFF0000FFFF0000uL;
num ^= num9;
num3 ^= num9;
num9 = (num2 ^ num4) & 0xFFFF0000FFFF00L;
num2 ^= num9;
num4 ^= num9;
num9 = (num5 ^ num7) & 0xFFFF0000FFFF0000uL;
num5 ^= num9;
num7 ^= num9;
num9 = (num6 ^ num8) & 0xFFFF0000FFFF00L;
num6 ^= num9;
num8 ^= num9;
num9 = (num ^ num5) & 0xFFFFFFFF00000000uL;
num ^= num9;
num5 ^= num9;
num9 = (num2 ^ num6) & 0xFFFFFFFF000000L;
num2 ^= num9;
num6 ^= num9;
num9 = (num3 ^ num7) & 0xFFFFFFFF0000L;
num3 ^= num9;
num7 ^= num9;
num9 = (num4 ^ num8) & 0xFFFFFFFF00L;
num4 ^= num9;
num8 ^= num9;
internalState[0] = num;
internalState[1] = num2;
internalState[2] = num3;
internalState[3] = num4;
internalState[4] = num5;
internalState[5] = num6;
internalState[6] = num7;
internalState[7] = num8;
break;
}
default:
throw new InvalidOperationException("unsupported block length: only 128/256/512 are allowed");
}
}
private void AddRoundKey(int round)
{
ulong[] array = roundKeys[round];
for (int i = 0; i < wordsInBlock; i++)
{
ulong[] array3;
ulong[] array2 = (array3 = internalState);
int num = i;
nint num2 = num;
array2[num] = array3[num2] + array[i];
}
}
private void SubRoundKey(int round)
{
ulong[] array = roundKeys[round];
for (int i = 0; i < wordsInBlock; i++)
{
ulong[] array3;
ulong[] array2 = (array3 = internalState);
int num = i;
nint num2 = num;
array2[num] = array3[num2] - array[i];
}
}
private void XorRoundKey(int round)
{
ulong[] array = roundKeys[round];
for (int i = 0; i < wordsInBlock; i++)
{
ulong[] array3;
ulong[] array2 = (array3 = internalState);
int num = i;
nint num2 = num;
array2[num] = array3[num2] ^ array[i];
}
}
private static ulong MixColumn(ulong c)
{
ulong num = MulX(c);
ulong num2 = Rotate(8, c) ^ c;
num2 ^= Rotate(16, num2);
num2 ^= Rotate(48, c);
ulong x = MulX2(num2 ^ c ^ num);
return num2 ^ Rotate(32, x) ^ Rotate(40, num) ^ Rotate(48, num);
}
private void MixColumns()
{
for (int i = 0; i < wordsInBlock; i++)
{
internalState[i] = MixColumn(internalState[i]);
}
}
private static ulong MixColumnInv(ulong c)
{
ulong num = c;
num ^= Rotate(8, num);
num ^= Rotate(32, num);
num ^= Rotate(48, c);
ulong num2 = num ^ c;
ulong num3 = Rotate(48, c);
ulong num4 = Rotate(56, c);
ulong n = num2 ^ num4;
ulong num5 = Rotate(56, num2);
num5 ^= MulX(n);
ulong num6 = Rotate(16, num2) ^ c;
num6 ^= Rotate(40, MulX(num5) ^ c);
ulong num7 = num2 ^ num3;
num7 ^= MulX(num6);
ulong num8 = Rotate(16, num);
num8 ^= MulX(num7);
ulong num9 = num2 ^ Rotate(24, c) ^ num3 ^ num4;
num9 ^= MulX(num8);
ulong num10 = Rotate(32, num2) ^ c ^ num4;
num10 ^= MulX(num9);
return num ^ MulX(Rotate(40, num10));
}
private void MixColumnsInv()
{
for (int i = 0; i < wordsInBlock; i++)
{
internalState[i] = MixColumnInv(internalState[i]);
}
}
private static ulong MulX(ulong n)
{
return ((n & 0x7F7F7F7F7F7F7F7FL) << 1) ^ (((n & 0x8080808080808080uL) >> 7) * 29);
}
private static ulong MulX2(ulong n)
{
return ((n & 0x3F3F3F3F3F3F3F3FL) << 2) ^ (((n & 0x8080808080808080uL) >> 6) * 29) ^ (((n & 0x4040404040404040L) >> 6) * 29);
}
private static ulong Rotate(int n, ulong x)
{
return (x >> n) | (x << -n);
}
private void RotateLeft(ulong[] x, ulong[] z)
{
switch (wordsInBlock)
{
case 2:
{
ulong num13 = x[0];
ulong num14 = x[1];
z[0] = (num13 >> 56) | (num14 << 8);
z[1] = (num14 >> 56) | (num13 << 8);
break;
}
case 4:
{
ulong num9 = x[0];
ulong num10 = x[1];
ulong num11 = x[2];
ulong num12 = x[3];
z[0] = (num10 >> 24) | (num11 << 40);
z[1] = (num11 >> 24) | (num12 << 40);
z[2] = (num12 >> 24) | (num9 << 40);
z[3] = (num9 >> 24) | (num10 << 40);
break;
}
case 8:
{
ulong num = x[0];
ulong num2 = x[1];
ulong num3 = x[2];
ulong num4 = x[3];
ulong num5 = x[4];
ulong num6 = x[5];
ulong num7 = x[6];
ulong num8 = x[7];
z[0] = (num3 >> 24) | (num4 << 40);
z[1] = (num4 >> 24) | (num5 << 40);
z[2] = (num5 >> 24) | (num6 << 40);
z[3] = (num6 >> 24) | (num7 << 40);
z[4] = (num7 >> 24) | (num8 << 40);
z[5] = (num8 >> 24) | (num << 40);
z[6] = (num >> 24) | (num2 << 40);
z[7] = (num2 >> 24) | (num3 << 40);
break;
}
default:
throw new InvalidOperationException("unsupported block length: only 128/256/512 are allowed");
}
}
public virtual int GetBlockSize()
{
return wordsInBlock << 3;
}
public virtual void Reset()
{
Array.Clear(internalState, 0, internalState.Length);
}
}