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