1 module dcrypt.blockcipher.rijndael;
2 
3 import dcrypt.blockcipher.blockcipher;
4 
5 import std.conv:text;
6 
7 unittest {
8 	
9 	// test vectors from http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
10 	string[] test_keys = [
11 		// sp800-38a.pdf
12 		x"2b7e151628aed2a6abf7158809cf4f3c",
13 		x"8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b",
14 		x"603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
15 	];
16 	
17 	string[] test_plaintexts = [
18 		x"6bc1bee22e409f96e93d7e117393172a",
19 		x"6bc1bee22e409f96e93d7e117393172a",
20 		x"6bc1bee22e409f96e93d7e117393172a",
21 	];
22 	
23 	string[] test_ciphertexts = [
24 		x"3ad77bb40d7a3660a89ecaf32466ef97",
25 		x"bd334f1d6e45f25ff712a214571fa5cc",
26 		x"f3eed1bdb5d2a03c064b5a7e3db181f8",
27 	];
28 	
29 	blockCipherTest(new Rijndael128Engine, test_keys, test_plaintexts, test_ciphertexts);
30 	
31 	// test all block sizes (128, 160, 192, 244, 256)
32 	
33 	string []keys = [
34 		x"01010101010101010101010101010101",
35 		x"0101010101010101010101010101010101010101",
36 		x"010101010101010101010101010101010101010101010101",
37 		x"01010101010101010101010101010101010101010101010101010101",
38 		x"0101010101010101010101010101010101010101010101010101010101010101",
39 	];
40 	string[] plains128 = [
41 		x"01010101010101010101010101010101",
42 		x"01010101010101010101010101010101",
43 		x"01010101010101010101010101010101",
44 		x"01010101010101010101010101010101",
45 		x"01010101010101010101010101010101",
46 	];
47 	string[] ciphers128 = [
48 		x"5e77e59f8f85943489a24149c75f4ec9",
49 		x"9ff7852b6881845bbb93e90261db12de",
50 		x"98b895a145ca4e0bf83e693281c1a097",
51 		x"168d2318e4fc720c8ee355771574fe58",
52 		x"9cac94c6b48561f8ffaaa78616ba4892",
53 	];
54 	
55 	blockCipherTest(new Rijndael128Engine, keys, plains128, ciphers128);
56 	
57 	string[] plains160 = [
58 		x"0101010101010101010101010101010101010101",
59 		x"0101010101010101010101010101010101010101",
60 		x"0101010101010101010101010101010101010101",
61 		x"0101010101010101010101010101010101010101",
62 		x"0101010101010101010101010101010101010101",
63 	];
64 	string[] ciphers160 = [
65 		x"0506b1bf13143240557b6356110a7ef75429535c",
66 		x"d69122f92262abfc4ccc79233635e64e4ab8d720",
67 		x"88219b6c6546e2d823323206ffb280035d28e615",
68 		x"8436e3478b3dbecbf789fede44c1b170e1e6442c",
69 		x"fef4057ed10ee8afcbae93d99591b39ba01758bd",
70 	];
71 	
72 	
73 	blockCipherTest(new Rijndael160Engine, keys, plains160, ciphers160);
74 	
75 	string[] plains192 = [
76 		x"010101010101010101010101010101010101010101010101",
77 		x"010101010101010101010101010101010101010101010101",
78 		x"010101010101010101010101010101010101010101010101",
79 		x"010101010101010101010101010101010101010101010101",
80 		x"010101010101010101010101010101010101010101010101",
81 	];
82 	string[] ciphers192 = [
83 		x"a64984768b532f6cec04216a3f858bb9c4a9f1469caa407f",
84 		x"8700141eba45ec66d1b386a5baaea6b9f1c996788e220ebc",
85 		x"c5c85078f586df206b6234a147facc9bf015f108f5da1200",
86 		x"c12d1c4fa4119aa539f8f637d73b6c27319734e8cf1f499f",
87 		x"18c0c2c37c137075749352ebec999f7c52d0e64cf15c3af5",
88 	];
89 	
90 	blockCipherTest(new Rijndael192Engine, keys, plains192, ciphers192);
91 	
92 	string[] plains224 = [
93 		x"01010101010101010101010101010101010101010101010101010101",
94 		x"01010101010101010101010101010101010101010101010101010101",
95 		x"01010101010101010101010101010101010101010101010101010101",
96 		x"01010101010101010101010101010101010101010101010101010101",
97 		x"01010101010101010101010101010101010101010101010101010101",
98 	];
99 	string[] ciphers224 = [
100 		x"4858261dd42a3b457102796e46586aac7d0b37e037a643e76ad27d34",
101 		x"4fdc0df3213efaf1fd5d44ca66fd04954d2370cd8beb596626da4d8c",
102 		x"69b308803d2ceca37a7ce4832761d4f027371df7451ca7458ca64f85",
103 		x"d2ab997da7cb0ccdbaa049715f8c17d3fbecd7e95b40ab814bfad96e",
104 		x"e6ff389d1fd554c3cbb3f72e62d76d146a4ab2f5fa24ec9d29a543de",
105 	];
106 	
107 	blockCipherTest(new Rijndael224Engine, keys, plains224, ciphers224);
108 	
109 	string[] plains256 = [
110 		x"0101010101010101010101010101010101010101010101010101010101010101",
111 		x"0101010101010101010101010101010101010101010101010101010101010101",
112 		x"0101010101010101010101010101010101010101010101010101010101010101",
113 		x"0101010101010101010101010101010101010101010101010101010101010101",
114 		x"0101010101010101010101010101010101010101010101010101010101010101",
115 	];
116 	string[] ciphers256 = [
117 		x"3ae837205c68ae9bec81d302601cc069cb0a3d712604a46b170377c981190143",
118 		x"e8c91ad4babd2909a575a866229a088ac9d9fad8c9e341a8bfbf647182c4ed7f",
119 		x"b4bc9135c8b8d291cd202700ce35bfa3a26b84cbdbff3817cb28b8f03283b608",
120 		x"821e0022e8864d31ba140e50c5c52e6c96b8bcb8c6f1173f57e1429ec9b1b43a",
121 		x"f6f97c6772f20488e3c0eec5482981b2bd00b15bbdf940069fbf5142ceb39688",
122 	];
123 	
124 	
125 	blockCipherTest(new Rijndael256Engine, keys, plains256, ciphers256);
126 }
127 
128 alias BlockCipherWrapper!(Rijndael!128) Rijndael128Engine; /// Rijndael with 128 bit blocks
129 alias BlockCipherWrapper!(Rijndael!160) Rijndael160Engine; /// Rijndael with 160 bit blocks
130 alias BlockCipherWrapper!(Rijndael!192) Rijndael192Engine; /// Rijndael with 192 bit blocks
131 alias BlockCipherWrapper!(Rijndael!224) Rijndael224Engine; /// Rijndael with 192 bit blocks
132 alias BlockCipherWrapper!(Rijndael!256) Rijndael256Engine; /// Rijndael with 256 bit blocks
133 
134 @safe
135 public struct Rijndael(uint blockBits) {
136 
137 	static assert(blockBits == 128 || blockBits == 160 || blockBits == 192 || blockBits == 224 || blockBits == 256, "unknown blocksize. Must be 128, 192, 224 or 256.");
138 
139 	alias ulong[4][MAXROUNDS+1] workingkey_t;
140 
141 	enum name = text("Rijndael", blockBits);
142 
143 	public {
144 	
145 		/// Params:
146 		/// forEncryption = `false`: decrypt, `true`: encrypt
147 		/// userKey = Secret key.
148 		/// iv = Not used.
149 		void start(bool forEncryption, in ubyte[] userKey, in ubyte[] iv = null) nothrow @nogc
150 		{
151 			this.forEncryption = forEncryption;
152 			workingKey = generateWorkingKey(userKey);
153 			initialized = true;
154 		}
155 
156 		uint processBlock(in ubyte[] input, ubyte[] output) nothrow @nogc
157 		in {
158 			assert(initialized, "Rijndael engine not initialized");
159 			assert(blockSize <= input.length, "input buffer too short");
160 			assert(blockSize <= output.length, "output buffer too short");
161 		}
162 		body {
163 			if (forEncryption)
164 			{
165 				unpackBlock(input);
166 				encryptBlock();
167 				packBlock(output);
168 			}
169 			else
170 			{
171 				unpackBlock(input);
172 				decryptBlock();
173 				packBlock(output);
174 			}
175 
176 			return blockSize;
177 		}
178 
179 		void reset() nothrow @nogc
180 		{
181 		}
182 
183 	}
184 
185 	
186 	// begin of private section
187 private:
188 
189 	
190 	/**
191 	 * multiply two elements of GF(2^m)
192 	 * needed for MixColumn and InvMixColumn
193 	 */
194 	@nogc
195 	private ubyte mul0x2(int b) pure nothrow
196 	{
197 		if (b != 0)
198 		{
199 			return aLogtable[25 + logtable[b]];
200 		}
201 		else
202 		{
203 			return 0;
204 		}
205 	}
206 
207 	@nogc
208 	private ubyte mul0x3(int b) pure nothrow
209 	{
210 		if (b != 0)
211 		{
212 			return aLogtable[1 + logtable[b]];
213 		}
214 		else
215 		{
216 			return 0;
217 		}
218 	}
219 
220 	@nogc
221 	private ubyte mul0x9(int b) pure nothrow
222 	{
223 		if (b >= 0)
224 		{
225 			return aLogtable[199 + b];
226 		}
227 		else
228 		{
229 			return 0;
230 		}
231 	}
232 
233 	@nogc
234 	private ubyte mul0xb(int b) pure nothrow
235 	{
236 		if (b >= 0)
237 		{
238 			return aLogtable[104 + b];
239 		}
240 		else
241 		{
242 			return 0;
243 		}
244 	}
245 
246 	@nogc
247 	private ubyte mul0xd(int b) pure nothrow
248 	{
249 		if (b >= 0)
250 		{
251 			return aLogtable[238 + b];
252 		}
253 		else
254 		{
255 			return 0;
256 		}
257 	}
258 
259 	@nogc
260 	private ubyte mul0xe(int b) pure nothrow
261 	{
262 		if (b >= 0)
263 		{
264 			return aLogtable[223 + b];
265 		}
266 		else
267 		{
268 			return 0;
269 		}
270 	}
271 
272 	/**
273 	 * xor corresponding text input and round key input bytes
274 	 */
275 	@nogc
276 	private void KeyAddition(in ulong[] rk) pure nothrow
277 	{
278 		A0 ^= rk[0];
279 		A1 ^= rk[1];
280 		A2 ^= rk[2];
281 		A3 ^= rk[3];
282 	}
283 
284 	@nogc
285 	private ulong shift(ulong r, uint shift) pure nothrow
286 	{
287 		return (((r >>> shift) | (r << (BC - shift)))) & BC_MASK;
288 	}
289 
290 	/**
291 	 * Row 0 remains unchanged
292 	 * The other three rows are shifted a variable amount
293 	 */
294 	@nogc
295 	private void ShiftRow(in ubyte[] shiftsSC) pure nothrow
296 	{
297 		A1 = shift(A1, shiftsSC[1]);
298 		A2 = shift(A2, shiftsSC[2]);
299 		A3 = shift(A3, shiftsSC[3]);
300 	}
301 
302 	@nogc
303 	private ulong applyS(ulong r, in ubyte[]  box) pure nothrow
304 	{
305 		ulong    res = 0;
306 
307 		for (uint j = 0; j < BC; j += 8)
308 		{
309 			res |= cast(ulong)(box[((r >> j) & 0xff)] & 0xff) << j;
310 		}
311 
312 		return res;
313 	}
314 
315 	/**
316 	 * Replace every byte of the input by the byte at that place
317 	 * in the nonlinear S-box
318 	 */
319 	@nogc
320 	private void Substitution(in ubyte[] box) pure nothrow
321 	{
322 		A0 = applyS(A0, box);
323 		A1 = applyS(A1, box);
324 		A2 = applyS(A2, box);
325 		A3 = applyS(A3, box);
326 	}
327 
328 	/**
329 	 * Mix the bytes of every column in a linear way
330 	 */
331 	@nogc
332 	private void MixColumn() pure nothrow
333 	{
334 		ulong r0, r1, r2, r3;
335 
336 		r0 = r1 = r2 = r3 = 0;
337 
338 		for (uint j = 0; j < BC; j += 8)
339 		{
340 			uint a0 = cast(uint)((A0 >> j) & 0xff);
341 			uint a1 = cast(uint)((A1 >> j) & 0xff);
342 			uint a2 = cast(uint)((A2 >> j) & 0xff);
343 			uint a3 = cast(uint)((A3 >> j) & 0xff);
344 
345 			r0 |= cast(ulong)((mul0x2(a0) ^ mul0x3(a1) ^ a2 ^ a3) & 0xff) << j;
346 
347 			r1 |= cast(ulong)((mul0x2(a1) ^ mul0x3(a2) ^ a3 ^ a0) & 0xff) << j;
348 
349 			r2 |= cast(ulong)((mul0x2(a2) ^ mul0x3(a3) ^ a0 ^ a1) & 0xff) << j;
350 
351 			r3 |= cast(ulong)((mul0x2(a3) ^ mul0x3(a0) ^ a1 ^ a2) & 0xff) << j;
352 		}
353 
354 		A0 = r0;
355 		A1 = r1;
356 		A2 = r2;
357 		A3 = r3;
358 	}
359 
360 	/**
361 	 * Mix the bytes of every column in a linear way
362 	 * This is the opposite operation of Mixcolumn
363 	 */
364 	@nogc
365 	private void InvMixColumn() pure nothrow
366 	{
367 		ulong r0, r1, r2, r3;
368 
369 		r0 = r1 = r2 = r3 = 0;
370 		for (uint j = 0; j < BC; j += 8)
371 		{
372 			uint a0 = cast(uint)((A0 >> j) & 0xff);
373 			uint a1 = cast(uint)((A1 >> j) & 0xff);
374 			uint a2 = cast(uint)((A2 >> j) & 0xff);
375 			uint a3 = cast(uint)((A3 >> j) & 0xff);
376 
377 			//
378 			// pre-lookup the log table
379 			//
380 			a0 = (a0 != 0) ? (logtable[a0 & 0xff]) : -1;
381 			a1 = (a1 != 0) ? (logtable[a1 & 0xff]) : -1;
382 			a2 = (a2 != 0) ? (logtable[a2 & 0xff]) : -1;
383 			a3 = (a3 != 0) ? (logtable[a3 & 0xff]) : -1;
384 
385 			r0 |= cast(ulong)((mul0xe(a0) ^ mul0xb(a1) ^ mul0xd(a2) ^ mul0x9(a3)) & 0xff) << j;
386 
387 			r1 |= cast(ulong)((mul0xe(a1) ^ mul0xb(a2) ^ mul0xd(a3) ^ mul0x9(a0)) & 0xff) << j;
388 
389 			r2 |= cast(ulong)((mul0xe(a2) ^ mul0xb(a3) ^ mul0xd(a0) ^ mul0x9(a1)) & 0xff) << j;
390 
391 			r3 |= cast(ulong)((mul0xe(a3) ^ mul0xb(a0) ^ mul0xd(a1) ^ mul0x9(a2)) & 0xff) << j;
392 		}
393 
394 		A0 = r0;
395 		A1 = r1;
396 		A2 = r2;
397 		A3 = r3;
398 	}
399 
400 	/**
401 	 * Calculate the necessary round keys
402 	 * The number of calculations depends on keyBits and blockBits
403 	 */
404 	private workingkey_t generateWorkingKey(in ubyte[] key) pure nothrow @nogc
405 	{
406 		uint         KC;
407 		uint         t, rconpointer = 0;
408 		uint         keyBits = cast(uint)(key.length * 8);
409 		ubyte[MAXKC][4]    tk;
410 		workingkey_t    W;
411 
412 		switch (keyBits)
413 		{
414 			case 128:
415 				KC = 4;
416 				break;
417 			case 160:
418 				KC = 5;
419 				break;
420 			case 192:
421 				KC = 6;
422 				break;
423 			case 224:
424 				KC = 7;
425 				break;
426 			case 256:
427 				KC = 8;
428 				break;
429 			default :
430 				assert(false, "Key length not 128/160/192/224/256 bits.");
431 		}
432 
433 		if (keyBits >= blockBits)
434 		{
435 			ROUNDS = KC + 6;
436 		}
437 		else
438 		{
439 			ROUNDS = (BC / 8) + 6;
440 		}
441 
442 		//
443 		// copy the key into the processing area
444 		//
445 		uint index = 0;
446 
447 		for (uint i = 0; i < key.length; i++)
448 		{
449 			tk[i % 4][i / 4] = key[index++];
450 		}
451 
452 		t = 0;
453 
454 		//
455 		// copy values into round key array
456 		//
457 		for (uint j = 0; (j < KC) && (t < (ROUNDS+1)*(BC / 8)); j++, t++)
458 		{
459 			for (uint i = 0; i < 4; i++)
460 			{
461 				W[t / (BC / 8)][i] |= cast(ulong)(tk[i][j] & 0xff) << ((t * 8) % BC);
462 			}
463 		}
464 
465 		//
466 		// while not enough round key material calculated
467 		// calculate new values
468 		//
469 		while (t < (ROUNDS+1)*(BC/8))
470 		{
471 			for (uint i = 0; i < 4; i++)
472 			{
473 				tk[i][0] ^= S[tk[(i+1)%4][KC-1] & 0xff];
474 			}
475 			tk[0][0] ^= rcon[rconpointer++];
476 
477 			if (KC <= 6)
478 			{
479 				for (uint j = 1; j < KC; j++)
480 				{
481 					for (uint i = 0; i < 4; i++)
482 					{
483 						tk[i][j] ^= tk[i][j-1];
484 					}
485 				}
486 			}
487 			else
488 			{
489 				for (uint j = 1; j < 4; j++)
490 				{
491 					for (uint i = 0; i < 4; i++)
492 					{
493 						tk[i][j] ^= tk[i][j-1];
494 					}
495 				}
496 				for (uint i = 0; i < 4; i++)
497 				{
498 					tk[i][4] ^= S[tk[i][3] & 0xff];
499 				}
500 				for (uint j = 5; j < KC; j++)
501 				{
502 					for (uint i = 0; i < 4; i++)
503 					{
504 						tk[i][j] ^= tk[i][j-1];
505 					}
506 				}
507 			}
508 
509 			//
510 			// copy values into round key array
511 			//
512 			for (uint j = 0; (j < KC) && (t < (ROUNDS+1)*(BC/8)); j++, t++)
513 			{
514 				for (uint i = 0; i < 4; i++)
515 				{
516 					W[t / (BC/8)][i] |= cast(ulong)(tk[i][j] & 0xff) << ((t * 8) % (BC));
517 				}
518 			}
519 		}
520 
521 		return W;
522 	}
523 
524 private:
525 
526 	uint         ROUNDS;
527 	workingkey_t    workingKey;
528 	ulong        A0, A1, A2, A3;
529 	bool forEncryption;
530 	bool initialized = false;
531 
532 	
533 	// set constants according to the block size
534 	static if(blockBits == 128) {
535 		enum BC = 32;
536 		enum BC_MASK = 0xffffffffL;
537 		immutable (ubyte)[] shifts0SC = [ 0, 8, 16, 24 ];
538 		immutable (ubyte)[] shifts1SC = [ 0, 24, 16, 8 ];
539 	} else 
540 	static if(blockBits == 160) {
541 		enum BC = 40;
542 		enum BC_MASK = 0xffffffffffL;
543 		immutable (ubyte)[] shifts0SC = [ 0, 8, 16, 24 ];
544 		immutable (ubyte)[] shifts1SC = [ 0, 32, 24, 16 ];
545 	} else 
546 	static if(blockBits == 192) {
547 		enum BC = 48;
548 		enum BC_MASK = 0xffffffffffffL;
549 		immutable (ubyte)[] shifts0SC = [ 0, 8, 16, 24 ];
550 		immutable (ubyte)[] shifts1SC = [ 0, 40, 32, 24 ];
551 	} else 
552 	static if(blockBits == 224) {
553 		enum BC = 56;
554 		enum BC_MASK = 0xffffffffffffffL;
555 		immutable (ubyte)[] shifts0SC = [ 0, 8, 16, 32 ];
556 		immutable (ubyte)[] shifts1SC = [ 0, 48, 40, 24 ];
557 	} else 
558 	static if(blockBits == 256) {
559 		enum BC = 64;
560 		enum BC_MASK = 0xffffffffffffffffL;
561 		immutable (ubyte)[] shifts0SC = [ 0, 8, 24, 32 ];
562 		immutable (ubyte)[] shifts1SC = [ 0, 56, 40, 32 ];
563 	} else {
564 		static assert(false, "invalid block size");
565 	}
566 	public enum blockSize = BC/2;
567 
568 	private nothrow @nogc:
569 
570 	void unpackBlock(in ubyte[] bytes)
571 	{
572 		uint     index = 0;
573 
574 		A0 = cast(ulong)(bytes[index++] & 0xff);
575 		A1 = cast(ulong)(bytes[index++] & 0xff);
576 		A2 = cast(ulong)(bytes[index++] & 0xff);
577 		A3 = cast(ulong)(bytes[index++] & 0xff);
578 
579 		for (uint j = 8; j != BC; j += 8)
580 		{
581 			A0 |= cast(ulong)(bytes[index++] & 0xff) << j;
582 			A1 |= cast(ulong)(bytes[index++] & 0xff) << j;
583 			A2 |= cast(ulong)(bytes[index++] & 0xff) << j;
584 			A3 |= cast(ulong)(bytes[index++] & 0xff) << j;
585 		}
586 	}
587 	
588 	@nogc
589 	void packBlock(ubyte[] bytes)
590 	{
591 		uint     index = 0;
592 
593 		for (uint j = 0; j != BC; j += 8)
594 		{
595 			bytes[index++] = cast(ubyte)(A0 >> j);
596 			bytes[index++] = cast(ubyte)(A1 >> j);
597 			bytes[index++] = cast(ubyte)(A2 >> j);
598 			bytes[index++] = cast(ubyte)(A3 >> j);
599 		}
600 	}
601 
602 	void encryptBlock()
603 	{
604 		alias workingKey rk;
605 		uint r;
606 
607 		//
608 		// begin with a key addition
609 		//
610 		KeyAddition(rk[0]);
611 
612 		//
613 		// ROUNDS-1 ordinary rounds
614 		//
615 		for (r = 1; r < ROUNDS; r++)
616 		{
617 			Substitution(S);
618 			ShiftRow(shifts0SC);
619 			MixColumn();
620 			KeyAddition(rk[r]);
621 		}
622 
623 		//
624 		// Last round is special: there is no MixColumn
625 		//
626 		Substitution(S);
627 		ShiftRow(shifts0SC);
628 		KeyAddition(rk[ROUNDS]);
629 	}
630 	
631 	void decryptBlock()
632 	{
633 		alias workingKey rk;
634 		uint r;
635 
636 		// To decrypt: apply the inverse operations of the encrypt routine,
637 		//             in opposite order
638 		//
639 		// (KeyAddition is an involution: it 's equal to its inverse)
640 		// (the inverse of Substitution with table S is Substitution with the inverse table of S)
641 		// (the inverse of Shiftrow is Shiftrow over a suitable distance)
642 		//
643 
644 		// First the special round:
645 		//   without InvMixColumn
646 		//   with extra KeyAddition
647 		//
648 		KeyAddition(rk[ROUNDS]);
649 		Substitution(Si);
650 		ShiftRow(shifts1SC);
651 
652 		//
653 		// ROUNDS-1 ordinary rounds
654 		//
655 		for (r = ROUNDS-1; r > 0; r--)
656 		{
657 			KeyAddition(rk[r]);
658 			InvMixColumn();
659 			Substitution(Si);
660 			ShiftRow(shifts1SC);
661 		}
662 
663 		//
664 		// End with the extra key addition
665 		//
666 		KeyAddition(rk[0]);
667 	}
668 
669 	// tables & constants
670 
671 	static immutable:
672 	
673 	enum MAXROUNDS = 14;
674 	
675 	enum MAXKC = (256/4);
676 	
677 	ubyte[256] logtable = [
678 		0,    0,    25,   1,    50,   2,    26,   198,
679 		75,   199,  27,   104,  51,   238,  223,  3,
680 		100,  4,    224,  14,   52,   141,  129,  239,
681 		76,   113,  8,    200,  248,  105,  28,   193,
682 		125,  194,  29,   181,  249,  185,  39,   106,
683 		77,   228,  166,  114,  154,  201,  9,    120,
684 		101,  47,   138,  5,    33,   15,   225,  36,
685 		18,   240,  130,  69,   53,   147,  218,  142,
686 		150,  143,  219,  189,  54,   208,  206,  148,
687 		19,   92,   210,  241,  64,   70,   131,  56,
688 		102,  221,  253,  48,   191,  6,    139,  98,
689 		179,  37,   226,  152,  34,   136,  145,  16,
690 		126,  110,  72,   195,  163,  182,  30,   66,
691 		58,   107,  40,   84,   250,  133,  61,   186,
692 		43,   121,  10,   21,   155,  159,  94,   202,
693 		78,   212,  172,  229,  243,  115,  167,  87,
694 		175,  88,   168,  80,   244,  234,  214,  116,
695 		79,   174,  233,  213,  231,  230,  173,  232,
696 		44,   215,  117,  122,  235,  22,   11,   245,
697 		89,   203,  95,   176,  156,  169,  81,   160,
698 		127,  12,   246,  111,  23,   196,  73,   236,
699 		216,  67,   31,   45,   164,  118,  123,  183,
700 		204,  187,  62,   90,   251,  96,   177,  134,
701 		59,   82,   161,  108,  170,  85,   41,   157,
702 		151,  178,  135,  144,  97,   190,  220,  252,
703 		188,  149,  207,  205,  55,   63,   91,   209,
704 		83,   57,   132,  60,   65,   162,  109,  71,
705 		20,   42,   158,  93,   86,   242,  211,  171,
706 		68,   17,   146,  217,  35,   32,   46,   137,
707 		180,  124,  184,  38,   119,  153,  227,  165,
708 		103,  74,   237,  222,  197,  49,   254,  24,
709 		13,   99,   140,  128,  192,  247,  112,  7
710 	];
711 	
712 	ubyte[511] aLogtable = [
713 		0,   3,   5,  15,  17,  51,  85, 255,  26,  46, 114, 150, 161, 248,  19,  53,
714 		95, 225,  56,  72, 216, 115, 149, 164, 247,   2,   6,  10,  30,  34, 102, 170,
715 		229,  52,  92, 228,  55,  89, 235,  38, 106, 190, 217, 112, 144, 171, 230,  49,
716 		83, 245,   4,  12,  20,  60,  68, 204,  79, 209, 104, 184, 211, 110, 178, 205,
717 		76, 212, 103, 169, 224,  59,  77, 215,  98, 166, 241,   8,  24,  40, 120, 136,
718 		131, 158, 185, 208, 107, 189, 220, 127, 129, 152, 179, 206,  73, 219, 118, 154,
719 		181, 196,  87, 249,  16,  48,  80, 240,  11,  29,  39, 105, 187, 214,  97, 163,
720 		254,  25,  43, 125, 135, 146, 173, 236,  47, 113, 147, 174, 233,  32,  96, 160,
721 		251,  22,  58,  78, 210, 109, 183, 194,  93, 231,  50,  86, 250,  21,  63,  65,
722 		195,  94, 226,  61,  71, 201,  64, 192,  91, 237,  44, 116, 156, 191, 218, 117,
723 		159, 186, 213, 100, 172, 239,  42, 126, 130, 157, 188, 223, 122, 142, 137, 128,
724 		155, 182, 193,  88, 232,  35, 101, 175, 234,  37, 111, 177, 200,  67, 197,  84,
725 		252,  31,  33,  99, 165, 244,   7,   9,  27,  45, 119, 153, 176, 203,  70, 202,
726 		69, 207,  74, 222, 121, 139, 134, 145, 168, 227,  62,  66, 198,  81, 243,  14,
727 		18,  54,  90, 238,  41, 123, 141, 140, 143, 138, 133, 148, 167, 242,  13,  23,
728 		57,  75, 221, 124, 132, 151, 162, 253,  28,  36, 108, 180, 199,  82, 246,   1,
729 		3,   5,  15,  17,  51,  85, 255,  26,  46, 114, 150, 161, 248,  19,  53,
730 		95, 225,  56,  72, 216, 115, 149, 164, 247,   2,   6,  10,  30,  34, 102, 170,
731 		229,  52,  92, 228,  55,  89, 235,  38, 106, 190, 217, 112, 144, 171, 230,  49,
732 		83, 245,   4,  12,  20,  60,  68, 204,  79, 209, 104, 184, 211, 110, 178, 205,
733 		76, 212, 103, 169, 224,  59,  77, 215,  98, 166, 241,   8,  24,  40, 120, 136,
734 		131, 158, 185, 208, 107, 189, 220, 127, 129, 152, 179, 206,  73, 219, 118, 154,
735 		181, 196,  87, 249,  16,  48,  80, 240,  11,  29,  39, 105, 187, 214,  97, 163,
736 		254,  25,  43, 125, 135, 146, 173, 236,  47, 113, 147, 174, 233,  32,  96, 160,
737 		251,  22,  58,  78, 210, 109, 183, 194,  93, 231,  50,  86, 250,  21,  63,  65,
738 		195,  94, 226,  61,  71, 201,  64, 192,  91, 237,  44, 116, 156, 191, 218, 117,
739 		159, 186, 213, 100, 172, 239,  42, 126, 130, 157, 188, 223, 122, 142, 137, 128,
740 		155, 182, 193,  88, 232,  35, 101, 175, 234,  37, 111, 177, 200,  67, 197,  84,
741 		252,  31,  33,  99, 165, 244,   7,   9,  27,  45, 119, 153, 176, 203,  70, 202,
742 		69, 207,  74, 222, 121, 139, 134, 145, 168, 227,  62,  66, 198,  81, 243,  14,
743 		18,  54,  90, 238,  41, 123, 141, 140, 143, 138, 133, 148, 167, 242,  13,  23,
744 		57,  75, 221, 124, 132, 151, 162, 253,  28,  36, 108, 180, 199,  82, 246,   1,
745 	];
746 	
747 	ubyte[256] S = [
748 		99, 124, 119, 123, 242, 107, 111, 197,  48,   1, 103,  43, 254, 215, 171, 118,
749 		202, 130, 201, 125, 250,  89,  71, 240, 173, 212, 162, 175, 156, 164, 114, 192,
750 		183, 253, 147,  38,  54,  63, 247, 204,  52, 165, 229, 241, 113, 216,  49,  21,
751 		4, 199,  35, 195,  24, 150,   5, 154,   7,  18, 128, 226, 235,  39, 178, 117,
752 		9, 131,  44,  26,  27, 110,  90, 160,  82,  59, 214, 179,  41, 227,  47, 132,
753 		83, 209,   0, 237,  32, 252, 177,  91, 106, 203, 190,  57,  74,  76,  88, 207,
754 		208, 239, 170, 251,  67,  77,  51, 133,  69, 249,   2, 127,  80,  60, 159, 168,
755 		81, 163,  64, 143, 146, 157,  56, 245, 188, 182, 218,  33,  16, 255, 243, 210,
756 		205,  12,  19, 236,  95, 151,  68,  23, 196, 167, 126,  61, 100,  93,  25, 115,
757 		96, 129,  79, 220,  34,  42, 144, 136,  70, 238, 184,  20, 222,  94,  11, 219,
758 		224,  50,  58,  10,  73,   6,  36,  92, 194, 211, 172,  98, 145, 149, 228, 121,
759 		231, 200,  55, 109, 141, 213,  78, 169, 108,  86, 244, 234, 101, 122, 174,   8,
760 		186, 120,  37,  46,  28, 166, 180, 198, 232, 221, 116,  31,  75, 189, 139, 138,
761 		112,  62, 181, 102,  72,   3, 246,  14,  97,  53,  87, 185, 134, 193,  29, 158,
762 		225, 248, 152,  17, 105, 217, 142, 148, 155,  30, 135, 233, 206,  85,  40, 223,
763 		140, 161, 137,  13, 191, 230,  66, 104,  65, 153,  45,  15, 176,  84, 187,  22,
764 	];
765 	
766 	ubyte[256] Si = [
767 		82,   9, 106, 213,  48,  54, 165,  56, 191,  64, 163, 158, 129, 243, 215, 251,
768 		124, 227,  57, 130, 155,  47, 255, 135,  52, 142,  67,  68, 196, 222, 233, 203,
769 		84, 123, 148,  50, 166, 194,  35,  61, 238,  76, 149,  11,  66, 250, 195,  78,
770 		8,  46, 161, 102,  40, 217,  36, 178, 118,  91, 162,  73, 109, 139, 209,  37,
771 		114, 248, 246, 100, 134, 104, 152,  22, 212, 164,  92, 204,  93, 101, 182, 146,
772 		108, 112,  72,  80, 253, 237, 185, 218,  94,  21,  70,  87, 167, 141, 157, 132,
773 		144, 216, 171,   0, 140, 188, 211,  10, 247, 228,  88,   5, 184, 179,  69,   6,
774 		208,  44,  30, 143, 202,  63,  15,   2, 193, 175, 189,   3,   1,  19, 138, 107,
775 		58, 145,  17,  65,  79, 103, 220, 234, 151, 242, 207, 206, 240, 180, 230, 115,
776 		150, 172, 116,  34, 231, 173,  53, 133, 226, 249,  55, 232,  28, 117, 223, 110,
777 		71, 241,  26, 113,  29,  41, 197, 137, 111, 183,  98,  14, 170,  24, 190,  27,
778 		252,  86,  62,  75, 198, 210, 121,  32, 154, 219, 192, 254, 120, 205,  90, 244,
779 		31, 221, 168,  51, 136,   7, 199,  49, 177,  18,  16,  89,  39, 128, 236,  95,
780 		96,  81, 127, 169,  25, 181,  74,  13,  45, 229, 122, 159, 147, 201, 156, 239,
781 		160, 224,  59,  77, 174,  42, 245, 176, 200, 235, 187,  60, 131,  83, 153,  97,
782 		23,  43,   4, 126, 186, 119, 214,  38, 225, 105,  20,  99,  85,  33,  12, 125,
783 	];
784 	
785 	ubyte[30] rcon = [
786 		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 ];
787 
788 }