1 module dcrypt.blockcipher.aes;
2 
3 import dcrypt.blockcipher.blockcipher;
4 import dcrypt.exceptions;
5 import dcrypt.bitmanip;
6 
7 /// Test AES encryption and decryption of a single block with 128, 192 and 256 bits key length.
8 /// test vectors from http://www.inconteam.com/software-development/41-encryption/55-aes-test-vectors
9 @safe
10 unittest {
11 	
12 	static string[] test_keys = [
13 		x"2b7e151628aed2a6abf7158809cf4f3c",
14 		x"8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b",
15 		x"603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4",
16 		x"603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"
17 	];
18 
19 	static string[] test_plaintexts = [
20 		x"6bc1bee22e409f96e93d7e117393172a",
21 		x"6bc1bee22e409f96e93d7e117393172a",
22 		x"6bc1bee22e409f96e93d7e117393172a",
23 		x"ae2d8a571e03ac9c9eb76fac45af8e51"
24 	];
25 	
26 	static string[] test_ciphertexts = [
27 		x"3ad77bb40d7a3660a89ecaf32466ef97",
28 		x"bd334f1d6e45f25ff712a214571fa5cc",
29 		x"f3eed1bdb5d2a03c064b5a7e3db181f8",
30 		x"591ccb10d410ed26dc5ba74a31362870"
31 		
32 	];
33 	
34 	AESEngine t = new AESEngine();
35 	
36 	blockCipherTest(t, test_keys, test_plaintexts, test_ciphertexts);
37 	
38 }
39 
40 static assert(isBlockCipher!AES, "AES is not a block cipher!");
41 
42 /// OOP API wrapper for AES
43 alias BlockCipherWrapper!AES AESEngine;
44 
45 @safe
46 public struct AES
47 {
48 
49 	public enum name = "AES";
50 	public enum blockSize = 16;
51 
52 	public {
53 	
54 		/// Params:
55 		/// forEncryption = `false`: decrypt, `true`: encrypt
56 		/// userKey = Secret key.
57 		/// iv = Not used.
58 		void start(bool forEncryption, in ubyte[] userKey, in ubyte[] iv = null) nothrow @nogc
59 		in {
60 			size_t len = userKey.length;
61 			assert(len == 16 || len == 24 || len == 32, this.name~": Invalid key length (requires 16, 24 or 32 bytes)");
62 		}
63 		body {
64 			this.forEncryption = forEncryption;
65 			
66 			generateWorkingKey(userKey, forEncryption);
67 			
68 			initialized = true;
69 		}
70 
71 		uint processBlock(in ubyte[] input, ubyte[] output) nothrow @nogc
72 		in {
73 			assert(initialized, "AES engine not initialized");
74 			assert(blockSize<=input.length, "input buffer too short");
75 			assert(blockSize<=output.length, "output buffer too short");
76 		}
77 		body {
78 
79 			if (forEncryption)
80 			{
81 				unpackBlock(input);
82 				encryptBlock();
83 				packBlock(output);
84 			}
85 			else
86 			{
87 				unpackBlock(input);
88 				decryptBlock();
89 				packBlock(output);
90 			}
91 
92 			return blockSize;
93 		}
94 
95 		void reset() nothrow @nogc
96 		{
97 
98 		}
99 	}
100 
101 	// begin of private section
102 private:
103 
104 //	@safe @nogc nothrow
105 //	~this() {
106 //		import dcrypt.util: wipe;
107 //
108 //		wipe(workingKey);
109 //		wipe(C0, C1, C2, C3);
110 //	}
111 
112 	enum MAXROUNDS = 14;
113 
114 	uint ROUNDS; // Number of rounds depends on keysize
115 	uint C0, C1, C2, C3; // State
116 
117 	uint[4][MAXROUNDS+1] workingKey;
118 
119 	bool forEncryption;
120 	bool initialized;
121 
122 	
123 	// Sbox and its inverse
124 	static immutable ubyte[256] S = [
125 		0x63u, 0x7cu, 0x77u, 0x7bu, 0xf2u, 0x6bu, 0x6fu, 0xc5u,
126 		0x30u, 0x01u, 0x67u, 0x2bu, 0xfeu, 0xd7u, 0xabu, 0x76u,
127 		0xcau, 0x82u, 0xc9u, 0x7du, 0xfau, 0x59u, 0x47u, 0xf0u,
128 		0xadu, 0xd4u, 0xa2u, 0xafu, 0x9cu, 0xa4u, 0x72u, 0xc0u,
129 		0xb7u, 0xfdu, 0x93u, 0x26u, 0x36u, 0x3fu, 0xf7u, 0xccu,
130 		0x34u, 0xa5u, 0xe5u, 0xf1u, 0x71u, 0xd8u, 0x31u, 0x15u,
131 		0x04u, 0xc7u, 0x23u, 0xc3u, 0x18u, 0x96u, 0x05u, 0x9au,
132 		0x07u, 0x12u, 0x80u, 0xe2u, 0xebu, 0x27u, 0xb2u, 0x75u,
133 		0x09u, 0x83u, 0x2cu, 0x1au, 0x1bu, 0x6eu, 0x5au, 0xa0u,
134 		0x52u, 0x3bu, 0xd6u, 0xb3u, 0x29u, 0xe3u, 0x2fu, 0x84u,
135 		0x53u, 0xd1u, 0x00u, 0xedu, 0x20u, 0xfcu, 0xb1u, 0x5bu,
136 		0x6au, 0xcbu, 0xbeu, 0x39u, 0x4au, 0x4cu, 0x58u, 0xcfu,
137 		0xd0u, 0xefu, 0xaau, 0xfbu, 0x43u, 0x4du, 0x33u, 0x85u,
138 		0x45u, 0xf9u, 0x02u, 0x7fu, 0x50u, 0x3cu, 0x9fu, 0xa8u,
139 		0x51u, 0xa3u, 0x40u, 0x8fu, 0x92u, 0x9du, 0x38u, 0xf5u,
140 		0xbcu, 0xb6u, 0xdau, 0x21u, 0x10u, 0xffu, 0xf3u, 0xd2u,
141 		0xcdu, 0x0cu, 0x13u, 0xecu, 0x5fu, 0x97u, 0x44u, 0x17u,
142 		0xc4u, 0xa7u, 0x7eu, 0x3du, 0x64u, 0x5du, 0x19u, 0x73u,
143 		0x60u, 0x81u, 0x4fu, 0xdcu, 0x22u, 0x2au, 0x90u, 0x88u,
144 		0x46u, 0xeeu, 0xb8u, 0x14u, 0xdeu, 0x5eu, 0x0bu, 0xdbu,
145 		0xe0u, 0x32u, 0x3au, 0x0au, 0x49u, 0x06u, 0x24u, 0x5cu,
146 		0xc2u, 0xd3u, 0xacu, 0x62u, 0x91u, 0x95u, 0xe4u, 0x79u,
147 		0xe7u, 0xc8u, 0x37u, 0x6du, 0x8du, 0xd5u, 0x4eu, 0xa9u,
148 		0x6cu, 0x56u, 0xf4u, 0xeau, 0x65u, 0x7au, 0xaeu, 0x08u,
149 		0xbau, 0x78u, 0x25u, 0x2eu, 0x1cu, 0xa6u, 0xb4u, 0xc6u,
150 		0xe8u, 0xddu, 0x74u, 0x1fu, 0x4bu, 0xbdu, 0x8bu, 0x8au,
151 		0x70u, 0x3eu, 0xb5u, 0x66u, 0x48u, 0x03u, 0xf6u, 0x0eu,
152 		0x61u, 0x35u, 0x57u, 0xb9u, 0x86u, 0xc1u, 0x1du, 0x9eu,
153 		0xe1u, 0xf8u, 0x98u, 0x11u, 0x69u, 0xd9u, 0x8eu, 0x94u,
154 		0x9bu, 0x1eu, 0x87u, 0xe9u, 0xceu, 0x55u, 0x28u, 0xdfu,
155 		0x8cu, 0xa1u, 0x89u, 0x0du, 0xbfu, 0xe6u, 0x42u, 0x68u,
156 		0x41u, 0x99u, 0x2du, 0x0fu, 0xb0u, 0x54u, 0xbbu, 0x16u
157 	];
158 
159 	static immutable ubyte[256] Si = [
160 		0x52u, 0x09u, 0x6au, 0xd5u, 0x30u, 0x36u, 0xa5u, 0x38u,
161 		0xbfu, 0x40u, 0xa3u, 0x9eu, 0x81u, 0xf3u, 0xd7u, 0xfbu,
162 		0x7cu, 0xe3u, 0x39u, 0x82u, 0x9bu, 0x2fu, 0xffu, 0x87u,
163 		0x34u, 0x8eu, 0x43u, 0x44u, 0xc4u, 0xdeu, 0xe9u, 0xcbu,
164 		0x54u, 0x7bu, 0x94u, 0x32u, 0xa6u, 0xc2u, 0x23u, 0x3du,
165 		0xeeu, 0x4cu, 0x95u, 0x0bu, 0x42u, 0xfau, 0xc3u, 0x4eu,
166 		0x08u, 0x2eu, 0xa1u, 0x66u, 0x28u, 0xd9u, 0x24u, 0xb2u,
167 		0x76u, 0x5bu, 0xa2u, 0x49u, 0x6du, 0x8bu, 0xd1u, 0x25u,
168 		0x72u, 0xf8u, 0xf6u, 0x64u, 0x86u, 0x68u, 0x98u, 0x16u,
169 		0xd4u, 0xa4u, 0x5cu, 0xccu, 0x5du, 0x65u, 0xb6u, 0x92u,
170 		0x6cu, 0x70u, 0x48u, 0x50u, 0xfdu, 0xedu, 0xb9u, 0xdau,
171 		0x5eu, 0x15u, 0x46u, 0x57u, 0xa7u, 0x8du, 0x9du, 0x84u,
172 		0x90u, 0xd8u, 0xabu, 0x00u, 0x8cu, 0xbcu, 0xd3u, 0x0au,
173 		0xf7u, 0xe4u, 0x58u, 0x05u, 0xb8u, 0xb3u, 0x45u, 0x06u,
174 		0xd0u, 0x2cu, 0x1eu, 0x8fu, 0xcau, 0x3fu, 0x0fu, 0x02u,
175 		0xc1u, 0xafu, 0xbdu, 0x03u, 0x01u, 0x13u, 0x8au, 0x6bu,
176 		0x3au, 0x91u, 0x11u, 0x41u, 0x4fu, 0x67u, 0xdcu, 0xeau,
177 		0x97u, 0xf2u, 0xcfu, 0xceu, 0xf0u, 0xb4u, 0xe6u, 0x73u,
178 		0x96u, 0xacu, 0x74u, 0x22u, 0xe7u, 0xadu, 0x35u, 0x85u,
179 		0xe2u, 0xf9u, 0x37u, 0xe8u, 0x1cu, 0x75u, 0xdfu, 0x6eu,
180 		0x47u, 0xf1u, 0x1au, 0x71u, 0x1du, 0x29u, 0xc5u, 0x89u,
181 		0x6fu, 0xb7u, 0x62u, 0x0eu, 0xaau, 0x18u, 0xbeu, 0x1bu,
182 		0xfcu, 0x56u, 0x3eu, 0x4bu, 0xc6u, 0xd2u, 0x79u, 0x20u,
183 		0x9au, 0xdbu, 0xc0u, 0xfeu, 0x78u, 0xcdu, 0x5au, 0xf4u,
184 		0x1fu, 0xddu, 0xa8u, 0x33u, 0x88u, 0x07u, 0xc7u, 0x31u,
185 		0xb1u, 0x12u, 0x10u, 0x59u, 0x27u, 0x80u, 0xecu, 0x5fu,
186 		0x60u, 0x51u, 0x7fu, 0xa9u, 0x19u, 0xb5u, 0x4au, 0x0du,
187 		0x2du, 0xe5u, 0x7au, 0x9fu, 0x93u, 0xc9u, 0x9cu, 0xefu,
188 		0xa0u, 0xe0u, 0x3bu, 0x4du, 0xaeu, 0x2au, 0xf5u, 0xb0u,
189 		0xc8u, 0xebu, 0xbbu, 0x3cu, 0x83u, 0x53u, 0x99u, 0x61u,
190 		0x17u, 0x2bu, 0x04u, 0x7eu, 0xbau, 0x77u, 0xd6u, 0x26u,
191 		0xe1u, 0x69u, 0x14u, 0x63u, 0x55u, 0x21u, 0x0cu, 0x7du
192 	];
193 
194 	// Round constants
195 	static immutable uint[30] rcon = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a,
196 		0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91
197 	];
198 
199 	// precomputation tables of calculations for rounds
200 	static immutable uint[256] T0 =
201 	[
202 		0xa56363c6u, 0x847c7cf8u, 0x997777eeu, 0x8d7b7bf6u, 0x0df2f2ffu,
203 		0xbd6b6bd6u, 0xb16f6fdeu, 0x54c5c591u, 0x50303060u, 0x03010102u,
204 		0xa96767ceu, 0x7d2b2b56u, 0x19fefee7u, 0x62d7d7b5u, 0xe6abab4du,
205 		0x9a7676ecu, 0x45caca8fu, 0x9d82821fu, 0x40c9c989u, 0x877d7dfau,
206 		0x15fafaefu, 0xeb5959b2u, 0xc947478eu, 0x0bf0f0fbu, 0xecadad41u,
207 		0x67d4d4b3u, 0xfda2a25fu, 0xeaafaf45u, 0xbf9c9c23u, 0xf7a4a453u,
208 		0x967272e4u, 0x5bc0c09bu, 0xc2b7b775u, 0x1cfdfde1u, 0xae93933du,
209 		0x6a26264cu, 0x5a36366cu, 0x413f3f7eu, 0x02f7f7f5u, 0x4fcccc83u,
210 		0x5c343468u, 0xf4a5a551u, 0x34e5e5d1u, 0x08f1f1f9u, 0x937171e2u,
211 		0x73d8d8abu, 0x53313162u, 0x3f15152au, 0x0c040408u, 0x52c7c795u,
212 		0x65232346u, 0x5ec3c39du, 0x28181830u, 0xa1969637u, 0x0f05050au,
213 		0xb59a9a2fu, 0x0907070eu, 0x36121224u, 0x9b80801bu, 0x3de2e2dfu,
214 		0x26ebebcdu, 0x6927274eu, 0xcdb2b27fu, 0x9f7575eau, 0x1b090912u,
215 		0x9e83831du, 0x742c2c58u, 0x2e1a1a34u, 0x2d1b1b36u, 0xb26e6edcu,
216 		0xee5a5ab4u, 0xfba0a05bu, 0xf65252a4u, 0x4d3b3b76u, 0x61d6d6b7u,
217 		0xceb3b37du, 0x7b292952u, 0x3ee3e3ddu, 0x712f2f5eu, 0x97848413u,
218 		0xf55353a6u, 0x68d1d1b9u, 0x00000000u, 0x2cededc1u, 0x60202040u,
219 		0x1ffcfce3u, 0xc8b1b179u, 0xed5b5bb6u, 0xbe6a6ad4u, 0x46cbcb8du,
220 		0xd9bebe67u, 0x4b393972u, 0xde4a4a94u, 0xd44c4c98u, 0xe85858b0u,
221 		0x4acfcf85u, 0x6bd0d0bbu, 0x2aefefc5u, 0xe5aaaa4fu, 0x16fbfbedu,
222 		0xc5434386u, 0xd74d4d9au, 0x55333366u, 0x94858511u, 0xcf45458au,
223 		0x10f9f9e9u, 0x06020204u, 0x817f7ffeu, 0xf05050a0u, 0x443c3c78u,
224 		0xba9f9f25u, 0xe3a8a84bu, 0xf35151a2u, 0xfea3a35du, 0xc0404080u,
225 		0x8a8f8f05u, 0xad92923fu, 0xbc9d9d21u, 0x48383870u, 0x04f5f5f1u,
226 		0xdfbcbc63u, 0xc1b6b677u, 0x75dadaafu, 0x63212142u, 0x30101020u,
227 		0x1affffe5u, 0x0ef3f3fdu, 0x6dd2d2bfu, 0x4ccdcd81u, 0x140c0c18u,
228 		0x35131326u, 0x2fececc3u, 0xe15f5fbeu, 0xa2979735u, 0xcc444488u,
229 		0x3917172eu, 0x57c4c493u, 0xf2a7a755u, 0x827e7efcu, 0x473d3d7au,
230 		0xac6464c8u, 0xe75d5dbau, 0x2b191932u, 0x957373e6u, 0xa06060c0u,
231 		0x98818119u, 0xd14f4f9eu, 0x7fdcdca3u, 0x66222244u, 0x7e2a2a54u,
232 		0xab90903bu, 0x8388880bu, 0xca46468cu, 0x29eeeec7u, 0xd3b8b86bu,
233 		0x3c141428u, 0x79dedea7u, 0xe25e5ebcu, 0x1d0b0b16u, 0x76dbdbadu,
234 		0x3be0e0dbu, 0x56323264u, 0x4e3a3a74u, 0x1e0a0a14u, 0xdb494992u,
235 		0x0a06060cu, 0x6c242448u, 0xe45c5cb8u, 0x5dc2c29fu, 0x6ed3d3bdu,
236 		0xefacac43u, 0xa66262c4u, 0xa8919139u, 0xa4959531u, 0x37e4e4d3u,
237 		0x8b7979f2u, 0x32e7e7d5u, 0x43c8c88bu, 0x5937376eu, 0xb76d6ddau,
238 		0x8c8d8d01u, 0x64d5d5b1u, 0xd24e4e9cu, 0xe0a9a949u, 0xb46c6cd8u,
239 		0xfa5656acu, 0x07f4f4f3u, 0x25eaeacfu, 0xaf6565cau, 0x8e7a7af4u,
240 		0xe9aeae47u, 0x18080810u, 0xd5baba6fu, 0x887878f0u, 0x6f25254au,
241 		0x722e2e5cu, 0x241c1c38u, 0xf1a6a657u, 0xc7b4b473u, 0x51c6c697u,
242 		0x23e8e8cbu, 0x7cdddda1u, 0x9c7474e8u, 0x211f1f3eu, 0xdd4b4b96u,
243 		0xdcbdbd61u, 0x868b8b0du, 0x858a8a0fu, 0x907070e0u, 0x423e3e7cu,
244 		0xc4b5b571u, 0xaa6666ccu, 0xd8484890u, 0x05030306u, 0x01f6f6f7u,
245 		0x120e0e1cu, 0xa36161c2u, 0x5f35356au, 0xf95757aeu, 0xd0b9b969u,
246 		0x91868617u, 0x58c1c199u, 0x271d1d3au, 0xb99e9e27u, 0x38e1e1d9u,
247 		0x13f8f8ebu, 0xb398982bu, 0x33111122u, 0xbb6969d2u, 0x70d9d9a9u,
248 		0x898e8e07u, 0xa7949433u, 0xb69b9b2du, 0x221e1e3cu, 0x92878715u,
249 		0x20e9e9c9u, 0x49cece87u, 0xff5555aau, 0x78282850u, 0x7adfdfa5u,
250 		0x8f8c8c03u, 0xf8a1a159u, 0x80898909u, 0x170d0d1au, 0xdabfbf65u,
251 		0x31e6e6d7u, 0xc6424284u, 0xb86868d0u, 0xc3414182u, 0xb0999929u,
252 		0x772d2d5au, 0x110f0f1eu, 0xcbb0b07bu, 0xfc5454a8u, 0xd6bbbb6du,
253 		0x3a16162cu];
254 
255 	static immutable uint[256] Tinv0 =
256 	[
257 		0x50a7f451u, 0x5365417eu, 0xc3a4171au, 0x965e273au, 0xcb6bab3bu,
258 		0xf1459d1fu, 0xab58faacu, 0x9303e34bu, 0x55fa3020u, 0xf66d76adu,
259 		0x9176cc88u, 0x254c02f5u, 0xfcd7e54fu, 0xd7cb2ac5u, 0x80443526u,
260 		0x8fa362b5u, 0x495ab1deu, 0x671bba25u, 0x980eea45u, 0xe1c0fe5du,
261 		0x02752fc3u, 0x12f04c81u, 0xa397468du, 0xc6f9d36bu, 0xe75f8f03u,
262 		0x959c9215u, 0xeb7a6dbfu, 0xda595295u, 0x2d83bed4u, 0xd3217458u,
263 		0x2969e049u, 0x44c8c98eu, 0x6a89c275u, 0x78798ef4u, 0x6b3e5899u,
264 		0xdd71b927u, 0xb64fe1beu, 0x17ad88f0u, 0x66ac20c9u, 0xb43ace7du,
265 		0x184adf63u, 0x82311ae5u, 0x60335197u, 0x457f5362u, 0xe07764b1u,
266 		0x84ae6bbbu, 0x1ca081feu, 0x942b08f9u, 0x58684870u, 0x19fd458fu,
267 		0x876cde94u, 0xb7f87b52u, 0x23d373abu, 0xe2024b72u, 0x578f1fe3u,
268 		0x2aab5566u, 0x0728ebb2u, 0x03c2b52fu, 0x9a7bc586u, 0xa50837d3u,
269 		0xf2872830u, 0xb2a5bf23u, 0xba6a0302u, 0x5c8216edu, 0x2b1ccf8au,
270 		0x92b479a7u, 0xf0f207f3u, 0xa1e2694eu, 0xcdf4da65u, 0xd5be0506u,
271 		0x1f6234d1u, 0x8afea6c4u, 0x9d532e34u, 0xa055f3a2u, 0x32e18a05u,
272 		0x75ebf6a4u, 0x39ec830bu, 0xaaef6040u, 0x069f715eu, 0x51106ebdu,
273 		0xf98a213eu, 0x3d06dd96u, 0xae053eddu, 0x46bde64du, 0xb58d5491u,
274 		0x055dc471u, 0x6fd40604u, 0xff155060u, 0x24fb9819u, 0x97e9bdd6u,
275 		0xcc434089u, 0x779ed967u, 0xbd42e8b0u, 0x888b8907u, 0x385b19e7u,
276 		0xdbeec879u, 0x470a7ca1u, 0xe90f427cu, 0xc91e84f8u, 0x00000000u,
277 		0x83868009u, 0x48ed2b32u, 0xac70111eu, 0x4e725a6cu, 0xfbff0efdu,
278 		0x5638850fu, 0x1ed5ae3du, 0x27392d36u, 0x64d90f0au, 0x21a65c68u,
279 		0xd1545b9bu, 0x3a2e3624u, 0xb1670a0cu, 0x0fe75793u, 0xd296eeb4u,
280 		0x9e919b1bu, 0x4fc5c080u, 0xa220dc61u, 0x694b775au, 0x161a121cu,
281 		0x0aba93e2u, 0xe52aa0c0u, 0x43e0223cu, 0x1d171b12u, 0x0b0d090eu,
282 		0xadc78bf2u, 0xb9a8b62du, 0xc8a91e14u, 0x8519f157u, 0x4c0775afu,
283 		0xbbdd99eeu, 0xfd607fa3u, 0x9f2601f7u, 0xbcf5725cu, 0xc53b6644u,
284 		0x347efb5bu, 0x7629438bu, 0xdcc623cbu, 0x68fcedb6u, 0x63f1e4b8u,
285 		0xcadc31d7u, 0x10856342u, 0x40229713u, 0x2011c684u, 0x7d244a85u,
286 		0xf83dbbd2u, 0x1132f9aeu, 0x6da129c7u, 0x4b2f9e1du, 0xf330b2dcu,
287 		0xec52860du, 0xd0e3c177u, 0x6c16b32bu, 0x99b970a9u, 0xfa489411u,
288 		0x2264e947u, 0xc48cfca8u, 0x1a3ff0a0u, 0xd82c7d56u, 0xef903322u,
289 		0xc74e4987u, 0xc1d138d9u, 0xfea2ca8cu, 0x360bd498u, 0xcf81f5a6u,
290 		0x28de7aa5u, 0x268eb7dau, 0xa4bfad3fu, 0xe49d3a2cu, 0x0d927850u,
291 		0x9bcc5f6au, 0x62467e54u, 0xc2138df6u, 0xe8b8d890u, 0x5ef7392eu,
292 		0xf5afc382u, 0xbe805d9fu, 0x7c93d069u, 0xa92dd56fu, 0xb31225cfu,
293 		0x3b99acc8u, 0xa77d1810u, 0x6e639ce8u, 0x7bbb3bdbu, 0x097826cdu,
294 		0xf418596eu, 0x01b79aecu, 0xa89a4f83u, 0x656e95e6u, 0x7ee6ffaau,
295 		0x08cfbc21u, 0xe6e815efu, 0xd99be7bau, 0xce366f4au, 0xd4099feau,
296 		0xd67cb029u, 0xafb2a431u, 0x31233f2au, 0x3094a5c6u, 0xc066a235u,
297 		0x37bc4e74u, 0xa6ca82fcu, 0xb0d090e0u, 0x15d8a733u, 0x4a9804f1u,
298 		0xf7daec41u, 0x0e50cd7fu, 0x2ff69117u, 0x8dd64d76u, 0x4db0ef43u,
299 		0x544daaccu, 0xdf0496e4u, 0xe3b5d19eu, 0x1b886a4cu, 0xb81f2cc1u,
300 		0x7f516546u, 0x04ea5e9du, 0x5d358c01u, 0x737487fau, 0x2e410bfbu,
301 		0x5a1d67b3u, 0x52d2db92u, 0x335610e9u, 0x1347d66du, 0x8c61d79au,
302 		0x7a0ca137u, 0x8e14f859u, 0x893c13ebu, 0xee27a9ceu, 0x35c961b7u,
303 		0xede51ce1u, 0x3cb1477au, 0x59dfd29cu, 0x3f73f255u, 0x79ce1418u,
304 		0xbf37c773u, 0xeacdf753u, 0x5baafd5fu, 0x146f3ddfu, 0x86db4478u,
305 		0x81f3afcau, 0x3ec468b9u, 0x2c342438u, 0x5f40a3c2u, 0x72c31d16u,
306 		0x0c25e2bcu, 0x8b493c28u, 0x41950dffu, 0x7101a839u, 0xdeb30c08u,
307 		0x9ce4b4d8u, 0x90c15664u, 0x6184cb7bu, 0x70b632d5u, 0x745c6c48u,
308 		0x4257b8d0u];
309 
310 	private enum uint  m1 = 0x80808080, m2 = 0x7f7f7f7f, m3 = 0x0000001b;;
311 
312 	@safe
313 	@nogc
314 	private static uint FFmulX(uint x) nothrow
315 	{
316 		return (((x & m2) << 1) ^ (((x & m1) >>> 7) * m3));
317 	}
318 
319 	@safe
320 	@nogc
321 	private static uint inv_mcol(uint x) nothrow
322 	{
323 		uint f2 = FFmulX(x);
324 		uint f4 = FFmulX(f2);
325 		uint f8 = FFmulX(f4);
326 		uint f9 = x ^ f8;
327 
328 		return f2 ^ f4 ^ f8 ^ rotateRight(f2 ^ f9, 8) ^ rotateRight(f4 ^ f9, 16) ^ rotateRight(f9, 24);
329 	}
330 
331 	@safe
332 	@nogc
333 	private static uint subWord(uint x) nothrow
334 	{
335 		return (S[x&255] | ((S[(x>>8)&255])<<8) | ((S[(x>>16)&255])<<16) | S[(x>>24)&255]<<24);
336 	}
337 
338 	/**
339 	 * Calculate the necessary round keys
340 	 * The number of calculations depends on key size and block size
341 	 * AES specified a fixed block size of 128 bits and key sizes 128/192/256 bits
342 	 * This code is written assuming those are the only possible values
343 	 */
344 	private void generateWorkingKey(in ubyte[] key, bool forEncryption) nothrow @nogc
345 	in {
346 		size_t len = key.length;
347 		assert(len == 16 || len == 24 || len == 32, this.name~": Invalid key length (requires 16, 24 or 32 bytes)");
348 	}
349 	body {
350 		uint KC = cast(uint)key.length / 4;  // key length in words
351 		uint t;
352 
353 		ROUNDS = KC + 6;  // This is not always true for the generalized Rijndael that allows larger block sizes
354 		//uint[][] W = new uint[][](ROUNDS+1,4);   // 4 words in a block
355 
356 		alias workingKey W;
357 
358 		//
359 		// copy the key into the round key array
360 		//
361 
362 		t = 0;
363 		uint i = 0;
364 		while (i < key.length)
365 		{
366 			W[t >> 2][t & 3] = (key[i]&0xff) | ((key[i+1]&0xff) << 8) | ((key[i+2]&0xff) << 16) | (key[i+3] << 24);
367 			i+=4;
368 			t++;
369 		}
370 
371 		//
372 		// while not enough round key material calculated
373 		// calculate new values
374 		//
375 		uint k = (ROUNDS + 1) << 2;
376 		for (i = KC; (i < k); i++)
377 		{
378 			int temp = W[(i-1)>>2][(i-1)&3];
379 			if ((i % KC) == 0)
380 			{
381 				temp = subWord(rotateRight(temp, 8)) ^ rcon[(i / KC)-1];
382 			}
383 			else if ((KC > 6) && ((i % KC) == 4))
384 			{
385 				temp = subWord(temp);
386 			}
387 
388 			W[i>>2][i&3] = W[(i - KC)>>2][(i-KC)&3] ^ temp;
389 		}
390 
391 		if (!forEncryption)
392 		{
393 			for (int j = 1; j < ROUNDS; j++)
394 			{
395 				for (i = 0; i < 4; i++)
396 				{
397 					W[j][i] = inv_mcol(W[j][i]);
398 				}
399 			}
400 		}
401 	}
402 
403 	
404 	@safe
405 	@nogc
406 	private void unpackBlock(in ubyte[] bytes) nothrow
407 	in {
408 		assert(bytes.length == 16, "invalid input length ");
409 	}
410 	body {
411 		C0 = (bytes[0]);
412 		C0 |= (bytes[1]) << 8;
413 		C0 |= (bytes[2]) << 16;
414 		C0 |= bytes[3] << 24;
415 		
416 
417 		C1 = (bytes[4]);
418 		C1 |= (bytes[5]) << 8;
419 		C1 |= (bytes[6]) << 16;
420 		C1 |= bytes[7] << 24;
421 		
422 
423 		C2 = (bytes[8]);
424 		C2 |= (bytes[9]) << 8;
425 		C2 |= (bytes[10]) << 16;
426 		C2 |= bytes[11] << 24;
427 
428 		
429 		C3 = (bytes[12]);
430 		C3 |= (bytes[13]) << 8;
431 		C3 |= (bytes[14]) << 16;
432 		C3 |= bytes[15] << 24;
433 		
434 	}
435 
436 	@safe
437 	@nogc
438 	private void packBlock(ubyte[] bytes) nothrow
439 	{
440 		bytes[0] = cast(ubyte)C0;
441 		bytes[1] = cast(ubyte)(C0 >> 8);
442 		bytes[2] = cast(ubyte)(C0 >> 16);
443 		bytes[3] = cast(ubyte)(C0 >> 24);
444 
445 		bytes[4] = cast(ubyte)C1;
446 		bytes[5] = cast(ubyte)(C1 >> 8);
447 		bytes[6] = cast(ubyte)(C1 >> 16);
448 		bytes[7] = cast(ubyte)(C1 >> 24);
449 
450 		bytes[8] = cast(ubyte)C2;
451 		bytes[9] = cast(ubyte)(C2 >> 8);
452 		bytes[10] = cast(ubyte)(C2 >> 16);
453 		bytes[11] = cast(ubyte)(C2 >> 24);
454 
455 		bytes[12] = cast(ubyte)C3;
456 		bytes[13] = cast(ubyte)(C3 >> 8);
457 		bytes[14] = cast(ubyte)(C3 >> 16);
458 		bytes[15] = cast(ubyte)(C3 >> 24);
459 	}
460 
461 	@safe
462 	@nogc
463 	private void encryptBlock() nothrow
464 	{
465 		alias workingKey wk;
466 		uint r, r0, r1, r2, r3;
467 
468 		C0 ^= wk[0][0];
469 		C1 ^= wk[0][1];
470 		C2 ^= wk[0][2];
471 		C3 ^= wk[0][3];
472 
473 		r = 1;
474 
475 		while (r < ROUNDS - 1)
476 		{
477 			r0 = T0[C0&255] ^ rotateRight(T0[(C1>>8)&255], 24) ^ rotateRight(T0[(C2>>16)&255],16) ^ rotateRight(T0[(C3>>24)&255],8) ^ wk[r][0];
478 			r1 = T0[C1&255] ^ rotateRight(T0[(C2>>8)&255], 24) ^ rotateRight(T0[(C3>>16)&255], 16) ^ rotateRight(T0[(C0>>24)&255], 8) ^ wk[r][1];
479 			r2 = T0[C2&255] ^ rotateRight(T0[(C3>>8)&255], 24) ^ rotateRight(T0[(C0>>16)&255], 16) ^ rotateRight(T0[(C1>>24)&255], 8) ^ wk[r][2];
480 			r3 = T0[C3&255] ^ rotateRight(T0[(C0>>8)&255], 24) ^ rotateRight(T0[(C1>>16)&255], 16) ^ rotateRight(T0[(C2>>24)&255], 8) ^ wk[r++][3];
481 			C0 = T0[r0&255] ^ rotateRight(T0[(r1>>8)&255], 24) ^ rotateRight(T0[(r2>>16)&255], 16) ^ rotateRight(T0[(r3>>24)&255], 8) ^ wk[r][0];
482 			C1 = T0[r1&255] ^ rotateRight(T0[(r2>>8)&255], 24) ^ rotateRight(T0[(r3>>16)&255], 16) ^ rotateRight(T0[(r0>>24)&255], 8) ^ wk[r][1];
483 			C2 = T0[r2&255] ^ rotateRight(T0[(r3>>8)&255], 24) ^ rotateRight(T0[(r0>>16)&255], 16) ^ rotateRight(T0[(r1>>24)&255], 8) ^ wk[r][2];
484 			C3 = T0[r3&255] ^ rotateRight(T0[(r0>>8)&255], 24) ^ rotateRight(T0[(r1>>16)&255], 16) ^ rotateRight(T0[(r2>>24)&255], 8) ^ wk[r++][3];
485 		}
486 
487 		r0 = T0[C0&255] ^ rotateRight(T0[(C1>>8)&255], 24) ^ rotateRight(T0[(C2>>16)&255], 16) ^ rotateRight(T0[(C3>>24)&255], 8) ^ wk[r][0];
488 		r1 = T0[C1&255] ^ rotateRight(T0[(C2>>8)&255], 24) ^ rotateRight(T0[(C3>>16)&255], 16) ^ rotateRight(T0[(C0>>24)&255], 8) ^ wk[r][1];
489 		r2 = T0[C2&255] ^ rotateRight(T0[(C3>>8)&255], 24) ^ rotateRight(T0[(C0>>16)&255], 16) ^ rotateRight(T0[(C1>>24)&255], 8) ^ wk[r][2];
490 		r3 = T0[C3&255] ^ rotateRight(T0[(C0>>8)&255], 24) ^ rotateRight(T0[(C1>>16)&255], 16) ^ rotateRight(T0[(C2>>24)&255], 8) ^ wk[r++][3];
491 
492 		// the final round's table is a simple function of S so we don't use a whole other four tables for it
493 
494 		C0 = (S[r0&255]) ^ ((S[(r1>>8)&255])<<8) ^ ((S[(r2>>16)&255])<<16) ^ (S[(r3>>24)&255]<<24) ^ wk[r][0];
495 		C1 = (S[r1&255]) ^ ((S[(r2>>8)&255])<<8) ^ ((S[(r3>>16)&255])<<16) ^ (S[(r0>>24)&255]<<24) ^ wk[r][1];
496 		C2 = (S[r2&255]) ^ ((S[(r3>>8)&255])<<8) ^ ((S[(r0>>16)&255])<<16) ^ (S[(r1>>24)&255]<<24) ^ wk[r][2];
497 		C3 = (S[r3&255]) ^ ((S[(r0>>8)&255])<<8) ^ ((S[(r1>>16)&255])<<16) ^ (S[(r2>>24)&255]<<24) ^ wk[r][3];
498 
499 	}
500 
501 	@safe @nogc
502 	private void decryptBlock() nothrow
503 	{
504 		alias workingKey wk;
505 
506 		uint r, r0, r1, r2, r3;
507 
508 		C0 ^= wk[ROUNDS][0];
509 		C1 ^= wk[ROUNDS][1];
510 		C2 ^= wk[ROUNDS][2];
511 		C3 ^= wk[ROUNDS][3];
512 
513 		r = ROUNDS-1;
514 
515 		while (r>1)
516 		{
517 			r0 = Tinv0[C0&255] ^ rotateRight(Tinv0[(C3>>8)&255], 24) ^ rotateRight(Tinv0[(C2>>16)&255], 16) ^ rotateRight(Tinv0[(C1>>24)&255], 8) ^ wk[r][0];
518 			r1 = Tinv0[C1&255] ^ rotateRight(Tinv0[(C0>>8)&255], 24) ^ rotateRight(Tinv0[(C3>>16)&255], 16) ^ rotateRight(Tinv0[(C2>>24)&255], 8) ^ wk[r][1];
519 			r2 = Tinv0[C2&255] ^ rotateRight(Tinv0[(C1>>8)&255], 24) ^ rotateRight(Tinv0[(C0>>16)&255], 16) ^ rotateRight(Tinv0[(C3>>24)&255], 8) ^ wk[r][2];
520 			r3 = Tinv0[C3&255] ^ rotateRight(Tinv0[(C2>>8)&255], 24) ^ rotateRight(Tinv0[(C1>>16)&255], 16) ^ rotateRight(Tinv0[(C0>>24)&255], 8) ^ wk[r--][3];
521 			C0 = Tinv0[r0&255] ^ rotateRight(Tinv0[(r3>>8)&255], 24) ^ rotateRight(Tinv0[(r2>>16)&255], 16) ^ rotateRight(Tinv0[(r1>>24)&255], 8) ^ wk[r][0];
522 			C1 = Tinv0[r1&255] ^ rotateRight(Tinv0[(r0>>8)&255], 24) ^ rotateRight(Tinv0[(r3>>16)&255], 16) ^ rotateRight(Tinv0[(r2>>24)&255], 8) ^ wk[r][1];
523 			C2 = Tinv0[r2&255] ^ rotateRight(Tinv0[(r1>>8)&255], 24) ^ rotateRight(Tinv0[(r0>>16)&255], 16) ^ rotateRight(Tinv0[(r3>>24)&255], 8) ^ wk[r][2];
524 			C3 = Tinv0[r3&255] ^ rotateRight(Tinv0[(r2>>8)&255], 24) ^ rotateRight(Tinv0[(r1>>16)&255], 16) ^ rotateRight(Tinv0[(r0>>24)&255], 8) ^ wk[r--][3];
525 		}
526 
527 		r0 = Tinv0[C0&255] ^ rotateRight(Tinv0[(C3>>8)&255], 24) ^ rotateRight(Tinv0[(C2>>16)&255], 16) ^ rotateRight(Tinv0[(C1>>24)&255], 8) ^ wk[r][0];
528 		r1 = Tinv0[C1&255] ^ rotateRight(Tinv0[(C0>>8)&255], 24) ^ rotateRight(Tinv0[(C3>>16)&255], 16) ^ rotateRight(Tinv0[(C2>>24)&255], 8) ^ wk[r][1];
529 		r2 = Tinv0[C2&255] ^ rotateRight(Tinv0[(C1>>8)&255], 24) ^ rotateRight(Tinv0[(C0>>16)&255], 16) ^ rotateRight(Tinv0[(C3>>24)&255], 8) ^ wk[r][2];
530 		r3 = Tinv0[C3&255] ^ rotateRight(Tinv0[(C2>>8)&255], 24) ^ rotateRight(Tinv0[(C1>>16)&255], 16) ^ rotateRight(Tinv0[(C0>>24)&255], 8) ^ wk[r][3];
531 
532 		// the final round's table is a simple function of Si so we don't use a whole other four tables for it
533 
534 		C0 = (Si[r0&255]) ^ ((Si[(r3>>8)&255])<<8) ^ ((Si[(r2>>16)&255])<<16) ^ (Si[(r1>>24)&255]<<24) ^ wk[0][0];
535 		C1 = (Si[r1&255]) ^ ((Si[(r0>>8)&255])<<8) ^ ((Si[(r3>>16)&255])<<16) ^ (Si[(r2>>24)&255]<<24) ^ wk[0][1];
536 		C2 = (Si[r2&255]) ^ ((Si[(r1>>8)&255])<<8) ^ ((Si[(r0>>16)&255])<<16) ^ (Si[(r3>>24)&255]<<24) ^ wk[0][2];
537 		C3 = (Si[r3&255]) ^ ((Si[(r2>>8)&255])<<8) ^ ((Si[(r1>>16)&255])<<16) ^ (Si[(r0>>24)&255]<<24) ^ wk[0][3];
538 	}
539 }