blob: 5a10634927fd6c8819f4ad7adde5e76439c1babb [file] [log] [blame]
// See file LICENSE for more information.
library impl.block_cipher.aes;
import 'dart:core';
import 'dart:typed_data';
import 'package:pointycastle/api.dart';
import 'package:pointycastle/src/impl/base_block_cipher.dart';
import 'package:pointycastle/src/registry/registry.dart';
import 'package:pointycastle/src/ufixnum.dart';
class AESEngine extends BaseBlockCipher {
static final FactoryConfig factoryConfig =
StaticFactoryConfig(BlockCipher, 'AES', () => AESEngine());
int _ROUNDS = 0;
late List<List<int>> _WorkingKey;
bool _forEncryption = false;
List<int> _s = List.empty();
static const _S = [
99,
124,
119,
123,
242,
107,
111,
197,
48,
1,
103,
43,
254,
215,
171,
118,
202,
130,
201,
125,
250,
89,
71,
240,
173,
212,
162,
175,
156,
164,
114,
192,
183,
253,
147,
38,
54,
63,
247,
204,
52,
165,
229,
241,
113,
216,
49,
21,
4,
199,
35,
195,
24,
150,
5,
154,
7,
18,
128,
226,
235,
39,
178,
117,
9,
131,
44,
26,
27,
110,
90,
160,
82,
59,
214,
179,
41,
227,
47,
132,
83,
209,
0,
237,
32,
252,
177,
91,
106,
203,
190,
57,
74,
76,
88,
207,
208,
239,
170,
251,
67,
77,
51,
133,
69,
249,
2,
127,
80,
60,
159,
168,
81,
163,
64,
143,
146,
157,
56,
245,
188,
182,
218,
33,
16,
255,
243,
210,
205,
12,
19,
236,
95,
151,
68,
23,
196,
167,
126,
61,
100,
93,
25,
115,
96,
129,
79,
220,
34,
42,
144,
136,
70,
238,
184,
20,
222,
94,
11,
219,
224,
50,
58,
10,
73,
6,
36,
92,
194,
211,
172,
98,
145,
149,
228,
121,
231,
200,
55,
109,
141,
213,
78,
169,
108,
86,
244,
234,
101,
122,
174,
8,
186,
120,
37,
46,
28,
166,
180,
198,
232,
221,
116,
31,
75,
189,
139,
138,
112,
62,
181,
102,
72,
3,
246,
14,
97,
53,
87,
185,
134,
193,
29,
158,
225,
248,
152,
17,
105,
217,
142,
148,
155,
30,
135,
233,
206,
85,
40,
223,
140,
161,
137,
13,
191,
230,
66,
104,
65,
153,
45,
15,
176,
84,
187,
22,
];
static const _Si = [
82,
9,
106,
213,
48,
54,
165,
56,
191,
64,
163,
158,
129,
243,
215,
251,
124,
227,
57,
130,
155,
47,
255,
135,
52,
142,
67,
68,
196,
222,
233,
203,
84,
123,
148,
50,
166,
194,
35,
61,
238,
76,
149,
11,
66,
250,
195,
78,
8,
46,
161,
102,
40,
217,
36,
178,
118,
91,
162,
73,
109,
139,
209,
37,
114,
248,
246,
100,
134,
104,
152,
22,
212,
164,
92,
204,
93,
101,
182,
146,
108,
112,
72,
80,
253,
237,
185,
218,
94,
21,
70,
87,
167,
141,
157,
132,
144,
216,
171,
0,
140,
188,
211,
10,
247,
228,
88,
5,
184,
179,
69,
6,
208,
44,
30,
143,
202,
63,
15,
2,
193,
175,
189,
3,
1,
19,
138,
107,
58,
145,
17,
65,
79,
103,
220,
234,
151,
242,
207,
206,
240,
180,
230,
115,
150,
172,
116,
34,
231,
173,
53,
133,
226,
249,
55,
232,
28,
117,
223,
110,
71,
241,
26,
113,
29,
41,
197,
137,
111,
183,
98,
14,
170,
24,
190,
27,
252,
86,
62,
75,
198,
210,
121,
32,
154,
219,
192,
254,
120,
205,
90,
244,
31,
221,
168,
51,
136,
7,
199,
49,
177,
18,
16,
89,
39,
128,
236,
95,
96,
81,
127,
169,
25,
181,
74,
13,
45,
229,
122,
159,
147,
201,
156,
239,
160,
224,
59,
77,
174,
42,
245,
176,
200,
235,
187,
60,
131,
83,
153,
97,
23,
43,
4,
126,
186,
119,
214,
38,
225,
105,
20,
99,
85,
33,
12,
125,
];
static const _rcon = [
0x01,
0x02,
0x04,
0x08,
0x10,
0x20,
0x40,
0x80,
0x1b,
0x36,
0x6c,
0xd8,
0xab,
0x4d,
0x9a,
0x2f,
0x5e,
0xbc,
0x63,
0xc6,
0x97,
0x35,
0x6a,
0xd4,
0xb3,
0x7d,
0xfa,
0xef,
0xc5,
0x91
];
static const _T0 = [
0xa56363c6,
0x847c7cf8,
0x997777ee,
0x8d7b7bf6,
0x0df2f2ff,
0xbd6b6bd6,
0xb16f6fde,
0x54c5c591,
0x50303060,
0x03010102,
0xa96767ce,
0x7d2b2b56,
0x19fefee7,
0x62d7d7b5,
0xe6abab4d,
0x9a7676ec,
0x45caca8f,
0x9d82821f,
0x40c9c989,
0x877d7dfa,
0x15fafaef,
0xeb5959b2,
0xc947478e,
0x0bf0f0fb,
0xecadad41,
0x67d4d4b3,
0xfda2a25f,
0xeaafaf45,
0xbf9c9c23,
0xf7a4a453,
0x967272e4,
0x5bc0c09b,
0xc2b7b775,
0x1cfdfde1,
0xae93933d,
0x6a26264c,
0x5a36366c,
0x413f3f7e,
0x02f7f7f5,
0x4fcccc83,
0x5c343468,
0xf4a5a551,
0x34e5e5d1,
0x08f1f1f9,
0x937171e2,
0x73d8d8ab,
0x53313162,
0x3f15152a,
0x0c040408,
0x52c7c795,
0x65232346,
0x5ec3c39d,
0x28181830,
0xa1969637,
0x0f05050a,
0xb59a9a2f,
0x0907070e,
0x36121224,
0x9b80801b,
0x3de2e2df,
0x26ebebcd,
0x6927274e,
0xcdb2b27f,
0x9f7575ea,
0x1b090912,
0x9e83831d,
0x742c2c58,
0x2e1a1a34,
0x2d1b1b36,
0xb26e6edc,
0xee5a5ab4,
0xfba0a05b,
0xf65252a4,
0x4d3b3b76,
0x61d6d6b7,
0xceb3b37d,
0x7b292952,
0x3ee3e3dd,
0x712f2f5e,
0x97848413,
0xf55353a6,
0x68d1d1b9,
0x00000000,
0x2cededc1,
0x60202040,
0x1ffcfce3,
0xc8b1b179,
0xed5b5bb6,
0xbe6a6ad4,
0x46cbcb8d,
0xd9bebe67,
0x4b393972,
0xde4a4a94,
0xd44c4c98,
0xe85858b0,
0x4acfcf85,
0x6bd0d0bb,
0x2aefefc5,
0xe5aaaa4f,
0x16fbfbed,
0xc5434386,
0xd74d4d9a,
0x55333366,
0x94858511,
0xcf45458a,
0x10f9f9e9,
0x06020204,
0x817f7ffe,
0xf05050a0,
0x443c3c78,
0xba9f9f25,
0xe3a8a84b,
0xf35151a2,
0xfea3a35d,
0xc0404080,
0x8a8f8f05,
0xad92923f,
0xbc9d9d21,
0x48383870,
0x04f5f5f1,
0xdfbcbc63,
0xc1b6b677,
0x75dadaaf,
0x63212142,
0x30101020,
0x1affffe5,
0x0ef3f3fd,
0x6dd2d2bf,
0x4ccdcd81,
0x140c0c18,
0x35131326,
0x2fececc3,
0xe15f5fbe,
0xa2979735,
0xcc444488,
0x3917172e,
0x57c4c493,
0xf2a7a755,
0x827e7efc,
0x473d3d7a,
0xac6464c8,
0xe75d5dba,
0x2b191932,
0x957373e6,
0xa06060c0,
0x98818119,
0xd14f4f9e,
0x7fdcdca3,
0x66222244,
0x7e2a2a54,
0xab90903b,
0x8388880b,
0xca46468c,
0x29eeeec7,
0xd3b8b86b,
0x3c141428,
0x79dedea7,
0xe25e5ebc,
0x1d0b0b16,
0x76dbdbad,
0x3be0e0db,
0x56323264,
0x4e3a3a74,
0x1e0a0a14,
0xdb494992,
0x0a06060c,
0x6c242448,
0xe45c5cb8,
0x5dc2c29f,
0x6ed3d3bd,
0xefacac43,
0xa66262c4,
0xa8919139,
0xa4959531,
0x37e4e4d3,
0x8b7979f2,
0x32e7e7d5,
0x43c8c88b,
0x5937376e,
0xb76d6dda,
0x8c8d8d01,
0x64d5d5b1,
0xd24e4e9c,
0xe0a9a949,
0xb46c6cd8,
0xfa5656ac,
0x07f4f4f3,
0x25eaeacf,
0xaf6565ca,
0x8e7a7af4,
0xe9aeae47,
0x18080810,
0xd5baba6f,
0x887878f0,
0x6f25254a,
0x722e2e5c,
0x241c1c38,
0xf1a6a657,
0xc7b4b473,
0x51c6c697,
0x23e8e8cb,
0x7cdddda1,
0x9c7474e8,
0x211f1f3e,
0xdd4b4b96,
0xdcbdbd61,
0x868b8b0d,
0x858a8a0f,
0x907070e0,
0x423e3e7c,
0xc4b5b571,
0xaa6666cc,
0xd8484890,
0x05030306,
0x01f6f6f7,
0x120e0e1c,
0xa36161c2,
0x5f35356a,
0xf95757ae,
0xd0b9b969,
0x91868617,
0x58c1c199,
0x271d1d3a,
0xb99e9e27,
0x38e1e1d9,
0x13f8f8eb,
0xb398982b,
0x33111122,
0xbb6969d2,
0x70d9d9a9,
0x898e8e07,
0xa7949433,
0xb69b9b2d,
0x221e1e3c,
0x92878715,
0x20e9e9c9,
0x49cece87,
0xff5555aa,
0x78282850,
0x7adfdfa5,
0x8f8c8c03,
0xf8a1a159,
0x80898909,
0x170d0d1a,
0xdabfbf65,
0x31e6e6d7,
0xc6424284,
0xb86868d0,
0xc3414182,
0xb0999929,
0x772d2d5a,
0x110f0f1e,
0xcbb0b07b,
0xfc5454a8,
0xd6bbbb6d,
0x3a16162c
];
static const _Tinv0 = [
0x50a7f451,
0x5365417e,
0xc3a4171a,
0x965e273a,
0xcb6bab3b,
0xf1459d1f,
0xab58faac,
0x9303e34b,
0x55fa3020,
0xf66d76ad,
0x9176cc88,
0x254c02f5,
0xfcd7e54f,
0xd7cb2ac5,
0x80443526,
0x8fa362b5,
0x495ab1de,
0x671bba25,
0x980eea45,
0xe1c0fe5d,
0x02752fc3,
0x12f04c81,
0xa397468d,
0xc6f9d36b,
0xe75f8f03,
0x959c9215,
0xeb7a6dbf,
0xda595295,
0x2d83bed4,
0xd3217458,
0x2969e049,
0x44c8c98e,
0x6a89c275,
0x78798ef4,
0x6b3e5899,
0xdd71b927,
0xb64fe1be,
0x17ad88f0,
0x66ac20c9,
0xb43ace7d,
0x184adf63,
0x82311ae5,
0x60335197,
0x457f5362,
0xe07764b1,
0x84ae6bbb,
0x1ca081fe,
0x942b08f9,
0x58684870,
0x19fd458f,
0x876cde94,
0xb7f87b52,
0x23d373ab,
0xe2024b72,
0x578f1fe3,
0x2aab5566,
0x0728ebb2,
0x03c2b52f,
0x9a7bc586,
0xa50837d3,
0xf2872830,
0xb2a5bf23,
0xba6a0302,
0x5c8216ed,
0x2b1ccf8a,
0x92b479a7,
0xf0f207f3,
0xa1e2694e,
0xcdf4da65,
0xd5be0506,
0x1f6234d1,
0x8afea6c4,
0x9d532e34,
0xa055f3a2,
0x32e18a05,
0x75ebf6a4,
0x39ec830b,
0xaaef6040,
0x069f715e,
0x51106ebd,
0xf98a213e,
0x3d06dd96,
0xae053edd,
0x46bde64d,
0xb58d5491,
0x055dc471,
0x6fd40604,
0xff155060,
0x24fb9819,
0x97e9bdd6,
0xcc434089,
0x779ed967,
0xbd42e8b0,
0x888b8907,
0x385b19e7,
0xdbeec879,
0x470a7ca1,
0xe90f427c,
0xc91e84f8,
0x00000000,
0x83868009,
0x48ed2b32,
0xac70111e,
0x4e725a6c,
0xfbff0efd,
0x5638850f,
0x1ed5ae3d,
0x27392d36,
0x64d90f0a,
0x21a65c68,
0xd1545b9b,
0x3a2e3624,
0xb1670a0c,
0x0fe75793,
0xd296eeb4,
0x9e919b1b,
0x4fc5c080,
0xa220dc61,
0x694b775a,
0x161a121c,
0x0aba93e2,
0xe52aa0c0,
0x43e0223c,
0x1d171b12,
0x0b0d090e,
0xadc78bf2,
0xb9a8b62d,
0xc8a91e14,
0x8519f157,
0x4c0775af,
0xbbdd99ee,
0xfd607fa3,
0x9f2601f7,
0xbcf5725c,
0xc53b6644,
0x347efb5b,
0x7629438b,
0xdcc623cb,
0x68fcedb6,
0x63f1e4b8,
0xcadc31d7,
0x10856342,
0x40229713,
0x2011c684,
0x7d244a85,
0xf83dbbd2,
0x1132f9ae,
0x6da129c7,
0x4b2f9e1d,
0xf330b2dc,
0xec52860d,
0xd0e3c177,
0x6c16b32b,
0x99b970a9,
0xfa489411,
0x2264e947,
0xc48cfca8,
0x1a3ff0a0,
0xd82c7d56,
0xef903322,
0xc74e4987,
0xc1d138d9,
0xfea2ca8c,
0x360bd498,
0xcf81f5a6,
0x28de7aa5,
0x268eb7da,
0xa4bfad3f,
0xe49d3a2c,
0x0d927850,
0x9bcc5f6a,
0x62467e54,
0xc2138df6,
0xe8b8d890,
0x5ef7392e,
0xf5afc382,
0xbe805d9f,
0x7c93d069,
0xa92dd56f,
0xb31225cf,
0x3b99acc8,
0xa77d1810,
0x6e639ce8,
0x7bbb3bdb,
0x097826cd,
0xf418596e,
0x01b79aec,
0xa89a4f83,
0x656e95e6,
0x7ee6ffaa,
0x08cfbc21,
0xe6e815ef,
0xd99be7ba,
0xce366f4a,
0xd4099fea,
0xd67cb029,
0xafb2a431,
0x31233f2a,
0x3094a5c6,
0xc066a235,
0x37bc4e74,
0xa6ca82fc,
0xb0d090e0,
0x15d8a733,
0x4a9804f1,
0xf7daec41,
0x0e50cd7f,
0x2ff69117,
0x8dd64d76,
0x4db0ef43,
0x544daacc,
0xdf0496e4,
0xe3b5d19e,
0x1b886a4c,
0xb81f2cc1,
0x7f516546,
0x04ea5e9d,
0x5d358c01,
0x737487fa,
0x2e410bfb,
0x5a1d67b3,
0x52d2db92,
0x335610e9,
0x1347d66d,
0x8c61d79a,
0x7a0ca137,
0x8e14f859,
0x893c13eb,
0xee27a9ce,
0x35c961b7,
0xede51ce1,
0x3cb1477a,
0x59dfd29c,
0x3f73f255,
0x79ce1418,
0xbf37c773,
0xeacdf753,
0x5baafd5f,
0x146f3ddf,
0x86db4478,
0x81f3afca,
0x3ec468b9,
0x2c342438,
0x5f40a3c2,
0x72c31d16,
0x0c25e2bc,
0x8b493c28,
0x41950dff,
0x7101a839,
0xdeb30c08,
0x9ce4b4d8,
0x90c15664,
0x6184cb7b,
0x70b632d5,
0x745c6c48,
0x4257b8d0
];
int _shift(int r, int shift) => rotr32(r, shift);
static const int _m1 = 0x80808080;
static const int _m2 = 0x7f7f7f7f;
static const int _m3 = 0x0000001b;
static const int _m4 = 0xC0C0C0C0;
static const int _m5 = 0x3f3f3f3f;
int _fFmulX(int x) {
var lsr = shiftr32(x & _m1, 7);
return ((x & _m2) << 1) ^ lsr * _m3;
}
int _fFmulX2(int x) {
var t0 = shiftl32(x & _m5, 2); // int t0 = (x & m5) << 2;
var t1 = x & _m4;
t1 ^= shiftr32(t1, 1);
return t0 ^ shiftr32(t1, 2) ^ shiftr32(t1, 5);
}
///
/// The following defines provide alternative definitions of FFmulX that might
/// give improved performance if a fast 32-bit multiply is not available.
/// private int FFmulX(int x) { int u = x & m1; u |= (u >> 1); return ((x & m2) << 1) ^ ((u >>> 3) | (u >>> 6)); }
/// private static final int m4 = 0x1b1b1b1b;
/// private int FFmulX(int x) { int u = x & m1; return ((x & m2) << 1) ^ ((u - (u >>> 7)) & m4); }
///
int _invMcol(int x) {
int t0, t1;
t0 = x;
t1 = t0 ^ _shift(t0, 8);
t0 ^= _fFmulX(t1);
t1 ^= _fFmulX2(t0);
t0 ^= t1 ^ _shift(t1, 16);
return t0;
}
int _subWord(int x) {
return _S[x & 255] & 255 |
((_S[(x >> 8) & 255] & 255) << 8) |
((_S[(x >> 16) & 255] & 255) << 16) |
_S[(x >> 24) & 255] << 24;
}
static const _BLOCK_SIZE = 16;
@override
String get algorithmName => 'AES';
@override
int get blockSize => _BLOCK_SIZE;
@override
void reset() {}
@override
void init(bool forEncryption, covariant KeyParameter params) {
_forEncryption = forEncryption;
_WorkingKey = generateWorkingKey(forEncryption, params);
if (_forEncryption) {
_s = List.from(_S);
} else {
_s = List.from(_Si);
}
}
List<List<int>> generateWorkingKey(bool forEncryption, KeyParameter params) {
var key = params.key;
var keyLen = key.length;
if (keyLen < 16 || keyLen > 32 || (keyLen & 7) != 0) {
throw ArgumentError('Key length not 128/192/256 bits.');
}
var KC = shiftr32(keyLen, 2);
_ROUNDS = KC +
6; // This is not always true for the generalized Rijndael that allows larger block sizes
var W = List.generate(
_ROUNDS + 1,
(int i) =>
List<int>.filled(4, 0, growable: false)); // 4 words in a block
switch (KC) {
case 4:
var col0 = unpack32(key, 0, Endian.little);
W[0][0] = col0;
var col1 = unpack32(key, 4, Endian.little);
W[0][1] = col1;
var col2 = unpack32(key, 8, Endian.little);
W[0][2] = col2;
var col3 = unpack32(key, 12, Endian.little);
W[0][3] = col3;
for (var i = 1; i <= 10; ++i) {
var colx = _subWord(_shift(col3, 8)) ^ _rcon[i - 1];
col0 ^= colx;
W[i][0] = col0;
col1 ^= col0;
W[i][1] = col1;
col2 ^= col1;
W[i][2] = col2;
col3 ^= col2;
W[i][3] = col3;
}
break;
case 6:
var col0 = unpack32(key, 0, Endian.little);
W[0][0] = col0;
var col1 = unpack32(key, 4, Endian.little);
W[0][1] = col1;
var col2 = unpack32(key, 8, Endian.little);
W[0][2] = col2;
var col3 = unpack32(key, 12, Endian.little);
W[0][3] = col3;
var col4 = unpack32(key, 16, Endian.little);
var col5 = unpack32(key, 20, Endian.little);
int i = 1, rcon = 1, colx;
for (;;) {
W[i][0] = col4;
W[i][1] = col5;
colx = _subWord(_shift(col5, 8)) ^ rcon;
rcon <<= 1;
col0 ^= colx;
W[i][2] = col0;
col1 ^= col0;
W[i][3] = col1;
col2 ^= col1;
W[i + 1][0] = col2;
col3 ^= col2;
W[i + 1][1] = col3;
col4 ^= col3;
W[i + 1][2] = col4;
col5 ^= col4;
W[i + 1][3] = col5;
colx = _subWord(_shift(col5, 8)) ^ rcon;
rcon <<= 1;
col0 ^= colx;
W[i + 2][0] = col0;
col1 ^= col0;
W[i + 2][1] = col1;
col2 ^= col1;
W[i + 2][2] = col2;
col3 ^= col2;
W[i + 2][3] = col3;
if ((i += 3) >= 13) {
break;
}
col4 ^= col3;
col5 ^= col4;
}
break;
case 8:
{
var col0 = unpack32(key, 0, Endian.little);
W[0][0] = col0;
var col1 = unpack32(key, 4, Endian.little);
W[0][1] = col1;
var col2 = unpack32(key, 8, Endian.little);
W[0][2] = col2;
var col3 = unpack32(key, 12, Endian.little);
W[0][3] = col3;
var col4 = unpack32(key, 16, Endian.little);
W[1][0] = col4;
var col5 = unpack32(key, 20, Endian.little);
W[1][1] = col5;
var col6 = unpack32(key, 24, Endian.little);
W[1][2] = col6;
var col7 = unpack32(key, 28, Endian.little);
W[1][3] = col7;
int i = 2, rcon = 1, colx;
for (;;) {
colx = _subWord(_shift(col7, 8)) ^ rcon;
rcon <<= 1;
col0 ^= colx;
W[i][0] = col0;
col1 ^= col0;
W[i][1] = col1;
col2 ^= col1;
W[i][2] = col2;
col3 ^= col2;
W[i][3] = col3;
++i;
if (i >= 15) {
break;
}
colx = _subWord(col3);
col4 ^= colx;
W[i][0] = col4;
col5 ^= col4;
W[i][1] = col5;
col6 ^= col5;
W[i][2] = col6;
col7 ^= col6;
W[i][3] = col7;
++i;
}
break;
}
default:
{
throw StateError('Should never get here');
}
}
if (!forEncryption) {
for (var j = 1; j < _ROUNDS; j++) {
for (var i = 0; i < 4; i++) {
W[j][i] = _invMcol(W[j][i]);
}
}
}
return W;
}
@override
int processBlock(Uint8List inp, int inpOff, Uint8List out, int outOff) {
if ((inpOff + (32 / 2)) > inp.lengthInBytes) {
throw ArgumentError('Input buffer too short');
}
if ((outOff + (32 / 2)) > out.lengthInBytes) {
throw ArgumentError('Output buffer too short');
}
if (_forEncryption) {
_encryptBlock(inp, inpOff, out, outOff, _WorkingKey);
} else {
_decryptBlock(inp, inpOff, out, outOff, _WorkingKey);
}
return _BLOCK_SIZE;
}
void _encryptBlock(
input, int inOff, Uint8List out, int outOff, List<List<int>> KW) {
var C0 = unpack32(input, inOff + 0, Endian.little);
var C1 = unpack32(input, inOff + 4, Endian.little);
var C2 = unpack32(input, inOff + 8, Endian.little);
var C3 = unpack32(input, inOff + 12, Endian.little);
var t0 = C0 ^ KW[0][0];
var t1 = C1 ^ KW[0][1];
var t2 = C2 ^ KW[0][2];
int r = 1, r0, r1, r2, r3 = C3 ^ KW[0][3];
while (r < _ROUNDS - 1) {
r0 = _T0[t0 & 255] ^
_shift(_T0[(t1 >> 8) & 255], 24) ^
_shift(_T0[(t2 >> 16) & 255], 16) ^
_shift(_T0[(r3 >> 24) & 255], 8) ^
KW[r][0];
r1 = _T0[t1 & 255] ^
_shift(_T0[(t2 >> 8) & 255], 24) ^
_shift(_T0[(r3 >> 16) & 255], 16) ^
_shift(_T0[(t0 >> 24) & 255], 8) ^
KW[r][1];
r2 = _T0[t2 & 255] ^
_shift(_T0[(r3 >> 8) & 255], 24) ^
_shift(_T0[(t0 >> 16) & 255], 16) ^
_shift(_T0[(t1 >> 24) & 255], 8) ^
KW[r][2];
r3 = _T0[r3 & 255] ^
_shift(_T0[(t0 >> 8) & 255], 24) ^
_shift(_T0[(t1 >> 16) & 255], 16) ^
_shift(_T0[(t2 >> 24) & 255], 8) ^
KW[r++][3];
t0 = _T0[r0 & 255] ^
_shift(_T0[(r1 >> 8) & 255], 24) ^
_shift(_T0[(r2 >> 16) & 255], 16) ^
_shift(_T0[(r3 >> 24) & 255], 8) ^
KW[r][0];
t1 = _T0[r1 & 255] ^
_shift(_T0[(r2 >> 8) & 255], 24) ^
_shift(_T0[(r3 >> 16) & 255], 16) ^
_shift(_T0[(r0 >> 24) & 255], 8) ^
KW[r][1];
t2 = _T0[r2 & 255] ^
_shift(_T0[(r3 >> 8) & 255], 24) ^
_shift(_T0[(r0 >> 16) & 255], 16) ^
_shift(_T0[(r1 >> 24) & 255], 8) ^
KW[r][2];
r3 = _T0[r3 & 255] ^
_shift(_T0[(r0 >> 8) & 255], 24) ^
_shift(_T0[(r1 >> 16) & 255], 16) ^
_shift(_T0[(r2 >> 24) & 255], 8) ^
KW[r++][3];
}
r0 = _T0[t0 & 255] ^
_shift(_T0[(t1 >> 8) & 255], 24) ^
_shift(_T0[(t2 >> 16) & 255], 16) ^
_shift(_T0[(r3 >> 24) & 255], 8) ^
KW[r][0];
r1 = _T0[t1 & 255] ^
_shift(_T0[(t2 >> 8) & 255], 24) ^
_shift(_T0[(r3 >> 16) & 255], 16) ^
_shift(_T0[(t0 >> 24) & 255], 8) ^
KW[r][1];
r2 = _T0[t2 & 255] ^
_shift(_T0[(r3 >> 8) & 255], 24) ^
_shift(_T0[(t0 >> 16) & 255], 16) ^
_shift(_T0[(t1 >> 24) & 255], 8) ^
KW[r][2];
r3 = _T0[r3 & 255] ^
_shift(_T0[(t0 >> 8) & 255], 24) ^
_shift(_T0[(t1 >> 16) & 255], 16) ^
_shift(_T0[(t2 >> 24) & 255], 8) ^
KW[r++][3];
// the final round's table is a simple function of S so we don't use a whole other four tables for it
C0 = (_S[r0 & 255] & 255) ^
((_S[(r1 >> 8) & 255] & 255) << 8) ^
((_s[(r2 >> 16) & 255] & 255) << 16) ^
(_s[(r3 >> 24) & 255] << 24) ^
KW[r][0];
C1 = (_s[r1 & 255] & 255) ^
((_S[(r2 >> 8) & 255] & 255) << 8) ^
((_S[(r3 >> 16) & 255] & 255) << 16) ^
(_s[(r0 >> 24) & 255] << 24) ^
KW[r][1];
C2 = (_s[r2 & 255] & 255) ^
((_S[(r3 >> 8) & 255] & 255) << 8) ^
((_S[(r0 >> 16) & 255] & 255) << 16) ^
(_S[(r1 >> 24) & 255] << 24) ^
KW[r][2];
C3 = (_s[r3 & 255] & 255) ^
((_s[(r0 >> 8) & 255] & 255) << 8) ^
((_s[(r1 >> 16) & 255] & 255) << 16) ^
(_S[(r2 >> 24) & 255] << 24) ^
KW[r][3];
pack32(C0, out, outOff + 0, Endian.little);
pack32(C1, out, outOff + 4, Endian.little);
pack32(C2, out, outOff + 8, Endian.little);
pack32(C3, out, outOff + 12, Endian.little);
}
void _decryptBlock(
input, int inOff, Uint8List out, int outOff, List<List<int>> KW) {
var C0 = unpack32(input, inOff + 0, Endian.little);
var C1 = unpack32(input, inOff + 4, Endian.little);
var C2 = unpack32(input, inOff + 8, Endian.little);
var C3 = unpack32(input, inOff + 12, Endian.little);
var t0 = C0 ^ KW[_ROUNDS][0];
var t1 = C1 ^ KW[_ROUNDS][1];
var t2 = C2 ^ KW[_ROUNDS][2];
int r = _ROUNDS - 1, r0, r1, r2, r3 = C3 ^ KW[_ROUNDS][3];
while (r > 1) {
r0 = _Tinv0[t0 & 255] ^
_shift(_Tinv0[(r3 >> 8) & 255], 24) ^
_shift(_Tinv0[(t2 >> 16) & 255], 16) ^
_shift(_Tinv0[(t1 >> 24) & 255], 8) ^
KW[r][0];
r1 = _Tinv0[t1 & 255] ^
_shift(_Tinv0[(t0 >> 8) & 255], 24) ^
_shift(_Tinv0[(r3 >> 16) & 255], 16) ^
_shift(_Tinv0[(t2 >> 24) & 255], 8) ^
KW[r][1];
r2 = _Tinv0[t2 & 255] ^
_shift(_Tinv0[(t1 >> 8) & 255], 24) ^
_shift(_Tinv0[(t0 >> 16) & 255], 16) ^
_shift(_Tinv0[(r3 >> 24) & 255], 8) ^
KW[r][2];
r3 = _Tinv0[r3 & 255] ^
_shift(_Tinv0[(t2 >> 8) & 255], 24) ^
_shift(_Tinv0[(t1 >> 16) & 255], 16) ^
_shift(_Tinv0[(t0 >> 24) & 255], 8) ^
KW[r--][3];
t0 = _Tinv0[r0 & 255] ^
_shift(_Tinv0[(r3 >> 8) & 255], 24) ^
_shift(_Tinv0[(r2 >> 16) & 255], 16) ^
_shift(_Tinv0[(r1 >> 24) & 255], 8) ^
KW[r][0];
t1 = _Tinv0[r1 & 255] ^
_shift(_Tinv0[(r0 >> 8) & 255], 24) ^
_shift(_Tinv0[(r3 >> 16) & 255], 16) ^
_shift(_Tinv0[(r2 >> 24) & 255], 8) ^
KW[r][1];
t2 = _Tinv0[r2 & 255] ^
_shift(_Tinv0[(r1 >> 8) & 255], 24) ^
_shift(_Tinv0[(r0 >> 16) & 255], 16) ^
_shift(_Tinv0[(r3 >> 24) & 255], 8) ^
KW[r][2];
r3 = _Tinv0[r3 & 255] ^
_shift(_Tinv0[(r2 >> 8) & 255], 24) ^
_shift(_Tinv0[(r1 >> 16) & 255], 16) ^
_shift(_Tinv0[(r0 >> 24) & 255], 8) ^
KW[r--][3];
}
r0 = _Tinv0[t0 & 255] ^
_shift(_Tinv0[(r3 >> 8) & 255], 24) ^
_shift(_Tinv0[(t2 >> 16) & 255], 16) ^
_shift(_Tinv0[(t1 >> 24) & 255], 8) ^
KW[r][0];
r1 = _Tinv0[t1 & 255] ^
_shift(_Tinv0[(t0 >> 8) & 255], 24) ^
_shift(_Tinv0[(r3 >> 16) & 255], 16) ^
_shift(_Tinv0[(t2 >> 24) & 255], 8) ^
KW[r][1];
r2 = _Tinv0[t2 & 255] ^
_shift(_Tinv0[(t1 >> 8) & 255], 24) ^
_shift(_Tinv0[(t0 >> 16) & 255], 16) ^
_shift(_Tinv0[(r3 >> 24) & 255], 8) ^
KW[r][2];
r3 = _Tinv0[r3 & 255] ^
_shift(_Tinv0[(t2 >> 8) & 255], 24) ^
_shift(_Tinv0[(t1 >> 16) & 255], 16) ^
_shift(_Tinv0[(t0 >> 24) & 255], 8) ^
KW[r][3];
// the final round's table is a simple function of Si so we don't use a whole other four tables for it
C0 = (_Si[r0 & 255] & 255) ^
((_s[(r3 >> 8) & 255] & 255) << 8) ^
((_s[(r2 >> 16) & 255] & 255) << 16) ^
(_Si[(r1 >> 24) & 255] << 24) ^
KW[0][0];
C1 = (_s[r1 & 255] & 255) ^
((_s[(r0 >> 8) & 255] & 255) << 8) ^
((_Si[(r3 >> 16) & 255] & 255) << 16) ^
(_s[(r2 >> 24) & 255] << 24) ^
KW[0][1];
C2 = (_s[r2 & 255] & 255) ^
((_Si[(r1 >> 8) & 255] & 255) << 8) ^
((_Si[(r0 >> 16) & 255] & 255) << 16) ^
(_s[(r3 >> 24) & 255] << 24) ^
KW[0][2];
C3 = (_Si[r3 & 255] & 255) ^
((_s[(r2 >> 8) & 255] & 255) << 8) ^
((_s[(r1 >> 16) & 255] & 255) << 16) ^
(_s[(r0 >> 24) & 255] << 24) ^
KW[0][3];
pack32(C0, out, outOff + 0, Endian.little);
pack32(C1, out, outOff + 4, Endian.little);
pack32(C2, out, outOff + 8, Endian.little);
pack32(C3, out, outOff + 12, Endian.little);
}
}