Dstu7624Engine
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Utilities;
using System;
namespace Org.BouncyCastle.Crypto.Engines
{
public class Dstu7624Engine : IBlockCipher
{
private ulong[] internalState;
private ulong[] workingKey;
private ulong[][] roundKeys;
private int wordsInBlock;
private int wordsInKey;
private const int ROUNDS_128 = 10;
private const int ROUNDS_256 = 14;
private const int ROUNDS_512 = 18;
private int roundsAmount;
private bool forEncryption;
private const ulong mdsMatrix = 290207332435296513;
private const ulong mdsInvMatrix = 14616231584692868525;
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,
byte.MaxValue,
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,
byte.MaxValue,
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,
byte.MaxValue,
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,
byte.MaxValue,
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,
byte.MaxValue,
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,
byte.MaxValue,
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,
byte.MaxValue,
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,
byte.MaxValue,
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 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];
internalState[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++) {
internalState[i] += array[i];
}
EncryptionRound();
for (int j = 0; j < internalState.Length; j++) {
internalState[j] ^= array2[j];
}
EncryptionRound();
for (int k = 0; k < internalState.Length; k++) {
internalState[k] += 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 = 281479271743489;
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++) {
internalState[k] ^= array2[k];
}
EncryptionRound();
for (int l = 0; l < wordsInBlock; l++) {
internalState[l] += 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 num3 = 0; num3 < wordsInBlock; num3++) {
internalState[num3] ^= array2[num3];
}
EncryptionRound();
for (int num4 = 0; num4 < wordsInBlock; num4++) {
internalState[num4] += array2[num4];
}
Array.Copy(internalState, 0, roundKeys[num], 0, wordsInBlock);
if (roundsAmount == num)
break;
}
num += 2;
num2 <<= 1;
ulong num5 = array[0];
for (int num6 = 1; num6 < array.Length; num6++) {
array[num6 - 1] = array[num6];
}
array[array.Length - 1] = num5;
}
}
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) {
if (wordsInBlock == 2)
EncryptBlock_128(input.AsSpan(inOff), output.AsSpan(outOff));
else {
Pack.LE_To_UInt64(input, inOff, internalState);
AddRoundKey(0);
int num = 0;
while (true) {
EncryptionRound();
if (++num == roundsAmount)
break;
XorRoundKey(num);
}
AddRoundKey(roundsAmount);
Pack.UInt64_To_LE(internalState, output, outOff);
Array.Clear(internalState, 0, internalState.Length);
}
} else if (wordsInBlock == 2) {
DecryptBlock_128(input.AsSpan(inOff), output.AsSpan(outOff));
} else {
Pack.LE_To_UInt64(input, inOff, internalState);
SubRoundKey(roundsAmount);
int num2 = roundsAmount;
while (true) {
DecryptionRound();
if (--num2 == 0)
break;
XorRoundKey(num2);
}
SubRoundKey(0);
Pack.UInt64_To_LE(internalState, output, outOff);
Array.Clear(internalState, 0, internalState.Length);
}
return GetBlockSize();
}
public virtual int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
{
if (workingKey == null)
throw new InvalidOperationException("Dstu7624Engine not initialised");
Check.DataLength(input, GetBlockSize(), "input buffer too short");
Check.OutputLength(output, GetBlockSize(), "output buffer too short");
if (forEncryption) {
if (wordsInBlock == 2)
EncryptBlock_128(input, output);
else {
Pack.LE_To_UInt64(input, internalState);
AddRoundKey(0);
int num = 0;
while (true) {
EncryptionRound();
if (++num == roundsAmount)
break;
XorRoundKey(num);
}
AddRoundKey(roundsAmount);
Pack.UInt64_To_LE(internalState, output);
Array.Clear(internalState, 0, internalState.Length);
}
} else if (wordsInBlock == 2) {
DecryptBlock_128(input, output);
} else {
Pack.LE_To_UInt64(input, internalState);
SubRoundKey(roundsAmount);
int num2 = roundsAmount;
while (true) {
DecryptionRound();
if (--num2 == 0)
break;
XorRoundKey(num2);
}
SubRoundKey(0);
Pack.UInt64_To_LE(internalState, output);
Array.Clear(internalState, 0, internalState.Length);
}
return GetBlockSize();
}
private void EncryptionRound()
{
SubBytes();
ShiftRows();
MixColumns();
}
private void DecryptionRound()
{
MixColumnsInv();
InvShiftRows();
InvSubBytes();
}
private void DecryptBlock_128(ReadOnlySpan<byte> input, Span<byte> output)
{
ulong num = Pack.LE_To_UInt64(input);
ulong num2 = Pack.LE_To_UInt64(input.Slice(8, input.Length - 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 num8 = T0[num4 & 255];
byte b = T1[(num4 >> 8) & 255];
byte b2 = T2[(num4 >> 16) & 255];
byte b3 = T3[num4 >> 24];
num4 = (uint)(num8 | (b << 8) | (b2 << 16) | (b3 << 24));
byte num9 = T0[num7 & 255];
byte b4 = T1[(num7 >> 8) & 255];
byte b5 = T2[(num7 >> 16) & 255];
byte b6 = T3[num7 >> 24];
num7 = (uint)(num9 | (b4 << 8) | (b5 << 16) | (b6 << 24));
num = (num4 | ((ulong)num7 << 32));
byte num10 = T0[num6 & 255];
byte b7 = T1[(num6 >> 8) & 255];
byte b8 = T2[(num6 >> 16) & 255];
byte b9 = T3[num6 >> 24];
num6 = (uint)(num10 | (b7 << 8) | (b8 << 16) | (b9 << 24));
byte num11 = T0[num5 & 255];
byte b10 = T1[(num5 >> 8) & 255];
byte b11 = T2[(num5 >> 16) & 255];
byte b12 = T3[num5 >> 24];
num5 = (uint)(num11 | (b10 << 8) | (b11 << 16) | (b12 << 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);
Pack.UInt64_To_LE(num2, output.Slice(8, output.Length - 8));
}
private void EncryptBlock_128(ReadOnlySpan<byte> input, Span<byte> output)
{
ulong num = Pack.LE_To_UInt64(input);
ulong num2 = Pack.LE_To_UInt64(input.Slice(8, input.Length - 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 num8 = S0[num4 & 255];
byte b = S1[(num4 >> 8) & 255];
byte b2 = S2[(num4 >> 16) & 255];
byte b3 = S3[num4 >> 24];
num4 = (uint)(num8 | (b << 8) | (b2 << 16) | (b3 << 24));
byte num9 = S0[num7 & 255];
byte b4 = S1[(num7 >> 8) & 255];
byte b5 = S2[(num7 >> 16) & 255];
byte b6 = S3[num7 >> 24];
num7 = (uint)(num9 | (b4 << 8) | (b5 << 16) | (b6 << 24));
num = (num4 | ((ulong)num7 << 32));
byte num10 = S0[num6 & 255];
byte b7 = S1[(num6 >> 8) & 255];
byte b8 = S2[(num6 >> 16) & 255];
byte b9 = S3[num6 >> 24];
num6 = (uint)(num10 | (b7 << 8) | (b8 << 16) | (b9 << 24));
byte num11 = S0[num5 & 255];
byte b10 = S1[(num5 >> 8) & 255];
byte b11 = S2[(num5 >> 16) & 255];
byte b12 = S3[num5 >> 24];
num5 = (uint)(num11 | (b10 << 8) | (b11 << 16) | (b12 << 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);
Pack.UInt64_To_LE(num2, output.Slice(8, output.Length - 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 num4 = S0[num2 & 255];
byte b = S1[(num2 >> 8) & 255];
byte b2 = S2[(num2 >> 16) & 255];
byte b3 = S3[num2 >> 24];
num2 = (uint)(num4 | (b << 8) | (b2 << 16) | (b3 << 24));
byte num5 = S0[num3 & 255];
byte b4 = S1[(num3 >> 8) & 255];
byte b5 = S2[(num3 >> 16) & 255];
byte b6 = S3[num3 >> 24];
num3 = (uint)(num5 | (b4 << 8) | (b5 << 16) | (b6 << 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 num4 = T0[num2 & 255];
byte b = T1[(num2 >> 8) & 255];
byte b2 = T2[(num2 >> 16) & 255];
byte b3 = T3[num2 >> 24];
num2 = (uint)(num4 | (b << 8) | (b2 << 16) | (b3 << 24));
byte num5 = T0[num3 & 255];
byte b4 = T1[(num3 >> 8) & 255];
byte b5 = T2[(num3 >> 16) & 255];
byte b6 = T3[num3 >> 24];
num3 = (uint)(num5 | (b4 << 8) | (b5 << 16) | (b6 << 24));
internalState[i] = (num2 | ((ulong)num3 << 32));
}
}
private void ShiftRows()
{
switch (wordsInBlock) {
case 2: {
ulong num15 = internalState[0];
ulong num16 = internalState[1];
ulong num17 = (ulong)((long)(num15 ^ num16) & -4294967296);
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 = (ulong)((long)(num10 ^ num12) & -4294967296);
num10 ^= num14;
num12 ^= num14;
num14 = ((num11 ^ num13) & 281474976645120);
num11 ^= num14;
num13 ^= num14;
num14 = (ulong)((long)(num10 ^ num11) & -281470681808896);
num10 ^= num14;
num11 ^= num14;
num14 = (ulong)((long)(num12 ^ num13) & -281470681808896);
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 = (ulong)((long)(num ^ num5) & -4294967296);
num ^= num9;
num5 ^= num9;
num9 = ((num2 ^ num6) & 72057594021150720);
num2 ^= num9;
num6 ^= num9;
num9 = ((num3 ^ num7) & 281474976645120);
num3 ^= num9;
num7 ^= num9;
num9 = ((num4 ^ num8) & 1099511627520);
num4 ^= num9;
num8 ^= num9;
num9 = (ulong)((long)(num ^ num3) & -281470681808896);
num ^= num9;
num3 ^= num9;
num9 = ((num2 ^ num4) & 72056494543077120);
num2 ^= num9;
num4 ^= num9;
num9 = (ulong)((long)(num5 ^ num7) & -281470681808896);
num5 ^= num9;
num7 ^= num9;
num9 = ((num6 ^ num8) & 72056494543077120);
num6 ^= num9;
num8 ^= num9;
num9 = (ulong)((long)(num ^ num2) & -71777214294589696);
num ^= num9;
num2 ^= num9;
num9 = (ulong)((long)(num3 ^ num4) & -71777214294589696);
num3 ^= num9;
num4 ^= num9;
num9 = (ulong)((long)(num5 ^ num6) & -71777214294589696);
num5 ^= num9;
num6 ^= num9;
num9 = (ulong)((long)(num7 ^ num8) & -71777214294589696);
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 = (ulong)((long)(num15 ^ num16) & -4294967296);
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 = (ulong)((long)(num10 ^ num11) & -281470681808896);
num10 ^= num14;
num11 ^= num14;
num14 = (ulong)((long)(num12 ^ num13) & -281470681808896);
num12 ^= num14;
num13 ^= num14;
num14 = (ulong)((long)(num10 ^ num12) & -4294967296);
num10 ^= num14;
num12 ^= num14;
num14 = ((num11 ^ num13) & 281474976645120);
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 = (ulong)((long)(num ^ num2) & -71777214294589696);
num ^= num9;
num2 ^= num9;
num9 = (ulong)((long)(num3 ^ num4) & -71777214294589696);
num3 ^= num9;
num4 ^= num9;
num9 = (ulong)((long)(num5 ^ num6) & -71777214294589696);
num5 ^= num9;
num6 ^= num9;
num9 = (ulong)((long)(num7 ^ num8) & -71777214294589696);
num7 ^= num9;
num8 ^= num9;
num9 = (ulong)((long)(num ^ num3) & -281470681808896);
num ^= num9;
num3 ^= num9;
num9 = ((num2 ^ num4) & 72056494543077120);
num2 ^= num9;
num4 ^= num9;
num9 = (ulong)((long)(num5 ^ num7) & -281470681808896);
num5 ^= num9;
num7 ^= num9;
num9 = ((num6 ^ num8) & 72056494543077120);
num6 ^= num9;
num8 ^= num9;
num9 = (ulong)((long)(num ^ num5) & -4294967296);
num ^= num9;
num5 ^= num9;
num9 = ((num2 ^ num6) & 72057594021150720);
num2 ^= num9;
num6 ^= num9;
num9 = ((num3 ^ num7) & 281474976645120);
num3 ^= num9;
num7 ^= num9;
num9 = ((num4 ^ num8) & 1099511627520);
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++) {
internalState[i] += array[i];
}
}
private void SubRoundKey(int round)
{
ulong[] array = roundKeys[round];
for (int i = 0; i < wordsInBlock; i++) {
internalState[i] -= array[i];
}
}
private void XorRoundKey(int round)
{
ulong[] array = roundKeys[round];
for (int i = 0; i < wordsInBlock; i++) {
internalState[i] ^= 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 ^ Rotate(8, c);
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 & 9187201950435737471) << 1) ^ (((ulong)((long)n & -9187201950435737472) >> 7) * 29);
}
private static ulong MulX2(ulong n)
{
return ((n & 4557430888798830399) << 2) ^ (((ulong)((long)n & -9187201950435737472) >> 6) * 29) ^ (((n & 4629771061636907072) >> 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;
}
}
}