1 module dcrypt.crypto.modes.gcm.gcm;
2 
3 public import dcrypt.crypto.modes.aead;
4 import dcrypt.crypto.modes.gcm.ghash;
5 import dcrypt.crypto.modes.gcm.multiplier;
6 
7 public import dcrypt.exceptions: InvalidCipherTextException, IllegalArgumentException;
8 
9 
10 /// Implementation of the Galois/Counter mode (GCM)
11 /// as described in NIST Special Publication 800-38D
12 /// 
13 /// Standards: NIST Special Publication 800-38D
14 
15 
16 // TODO Shoup tables
17 // TODO support for uneven macSize
18 
19 //alias GCMCipher(T) = AEADCipherWrapper!(GCM!T); // would be nice but does not yet work
20 
21 import dcrypt.crypto.engines.aes;
22 static assert(isAEADCipher!(GCM!AES), "GCM ist not a AEADCipher.");
23 
24 ///
25 ///	usage of OOP API:
26 ///	auto aes_gcm = new AEADCipherWrapper!(GCM!AES)();
27 ///
28 @safe
29 public struct GCM(T) if(is(T == void) || (isBlockCipher!T && T.blockSize == 16))
30 {
31 
32 	private enum OOP = is(T == void); // use OOP API
33 
34 	public enum blockSize = 16;
35 	public enum macSize = 16;
36 
37 	// if T == void: use OOP API for underlying block cipher
38 	static if(OOP) {
39 		/**
40 		 * Params:
41 		 * c = underlying BlockCipher
42 		 */
43 		public this(BlockCipher c)
44 		in {
45 			assert(c.blockSize() == blockSize, "GCM: block size of underlying cipher must be 128 bits!");	
46 		}
47 		body {
48 			blockCipher = c;
49 		}
50 	} else {
51 		static assert(T.blockSize == blockSize, "GCM: block size of underlying cipher must be 128 bits!");
52 	}
53 
54 	private {
55 
56 		static if(OOP) {
57 			BlockCipher blockCipher;
58 		} else {
59 			T blockCipher;	/// underlying BlockCipher
60 		}
61 
62 		GHash gHash;					/// provides the multiplication in GF(2^128) by H
63 		CircularBlockBuffer!blockSize buf;	/// stores input data before processing
64 
65 		ubyte[blockSize] Y;				/// counter
66 		ubyte[blockSize] E0;			/// E(key, Y0), needed to derive AuthTag from GHASH
67 		ubyte[blockSize] mac;			/// used to store the encrypted ghash TODO: use other buffer, e.g. E0 itself
68 		
69 		ubyte[blockSize] initialY;		/// used to reset Y
70 		
71 		bool forEncryption;				/// Tells wether we are in ecryption or decryption mode.
72 		bool initialized = false;		/// True if and only if GCM has been initialized
73 	}
74 
75 	public {
76 
77 		/**
78 		 * init cipher, H, Y0, E0
79 		 * 
80 		 * Params:
81 		 * forEncryption = encrypt (true) or decrypt (false)
82 		 * iv = Initialization vector. Length of 96 bits is most efficient.
83 		 * key = encryption key
84 		 * macSize = length of authentication tag in bits. 32 <= macSize <= 128. Only multiples of 8 supported.
85 		 * 
86 		 */
87 		void start(bool forEncryption, in ubyte[] key, in ubyte[] iv) nothrow @nogc
88 		in {
89 			assert(iv !is null, "Must provide an IV.");
90 		}
91 		body {
92 			
93 			this.forEncryption = forEncryption;
94 			
95 			// init underyling cipher
96 			blockCipher.start(true, key);
97 			
98 			// init gHash
99 			ubyte[blockSize] H;
100 			H[] = 0;
101 			blockCipher.processBlock(H,H); // calculate H=E(K,0^128);
102 			
103 			gHash.init(H);
104 			
105 			// init IV
106 			if(iv.length == 12) { // 96 bit IV is optimal
107 				Y[0..iv.length] = iv[];
108 				Y[$-1] = 1;
109 			}else {
110 				gHash.updateCipherData(iv);
111 				gHash.doFinal(Y);
112 			}
113 			
114 			// generate key stream used later to encrypt ghash
115 			genNextKeyStreamBlock(E0);
116 			
117 			initialY = Y; // remember this to reset the cipher
118 			
119 			initialized = true;
120 		}
121 		
122 		static if(OOP) {
123 			/**
124 			 * Returns: the algorithm name.
125 			 */
126 			string name() pure nothrow {
127 				return blockCipher.name ~ "/GCM";
128 			}
129 		} else {
130 			public enum name = T.name~"/GCM";
131 		}
132 
133 		static if(OOP) {
134 			/**
135 			 * Returns: the cipher this object wraps.
136 			 */
137 			BlockCipher getUnderlyingCipher() pure nothrow @nogc {
138 				return blockCipher;
139 			}
140 		} else {
141 			/**
142 			 * Returns: the cipher this object wraps.
143 			 */
144 			ref T getUnderlyingCipher() pure nothrow @nogc {
145 				return blockCipher;
146 			}
147 		}
148 		
149 		/**
150 		 * Add a sequence of bytes to the associated data check.
151 		 * 
152 		 * Params: in = the input byte array.
153 		 */
154 		void processAADBytes(in ubyte[] aad...) nothrow @nogc 
155 		in {
156 			assert(initialized, "not initialized");
157 		}
158 		body {
159 			gHash.updateAAD(aad);
160 		}
161 
162 		/**
163 		 * process a block of bytes from in putting the result into out.
164 		 * Params:
165 		 * in = the input byte array.
166 		 * out = the output buffer the processed bytes go into.
167 		 * Returns: Number of written bytes to output.
168 		 * Throws: Error if the output buffer is too small.
169 		 */
170 		size_t processBytes(in ubyte[] input, ubyte[] output) nothrow 
171 		in {
172 			assert(initialized, "not initialized");
173 			assert(output.length >= getUpdateOutputSize(input.length), "output buffer too short");
174 		}
175 		body {
176 
177 			import std.algorithm: min;
178 			size_t outputBytes = 0;
179 
180 			const(ubyte)[] iBuf = input;
181 
182 			while(iBuf.length > 0) {
183 				if(buf.isFull()) {
184 					// encrypt one block
185 					outputBlock(output);
186 					output = output[blockSize..$];
187 					outputBytes += blockSize;
188 				}
189 
190 				// copy max one block to the buffer
191 				size_t procLen = buf.put(iBuf);
192 				iBuf = iBuf[procLen..$];
193 			}
194 
195 			return outputBytes;
196 		}
197 		
198 		/**
199 		 * Finish the operation. Does not append mac tag to the cipher text.
200 		 * Mac tag does NOT get verified in decryption mode.
201 		 *
202 		 * Params: out = space for any resulting output data.
203 		 * Returns: number of bytes written into out.
204 		 */
205 		size_t finish(ubyte[] macBuf, ubyte[] output) nothrow
206 		in {
207 			assert(initialized, "not initialized");
208 
209 			assert(output.length >= buf.length, "output buffer too small");
210 			assert(macBuf.length == 16, "MAC buffer must be 16 bytes.");
211 		}
212 		body{
213 
214 			size_t outputBytes = 0;
215 
216 			//			if(!forEncryption) {
217 			//				if(buf.length < macLen) {
218 			//					throw new InvalidCipherTextException("ciphertext so short that it can't even contain the MAC");
219 			//				}
220 			//			}
221 
222 			size_t partialBlockLen = buf.length;
223 
224 			ubyte[2*blockSize] lastBlocks; // last two blocks. probably not full. last few bytes are the token.
225 
226 			
227 			// copy partial cipher data block
228 			buf.drainAll(lastBlocks);
229 
230 			assert(output.length >= partialBlockLen, "output buffer too short");
231 			// encrypt last partial block
232 			ubyte[2*blockSize] keyStream;
233 
234 			// generate two blocks of key stream
235 			genNextKeyStreamBlock(keyStream[0..blockSize]);
236 			genNextKeyStreamBlock(keyStream[blockSize..2*blockSize]);
237 
238 			output[0..partialBlockLen] = lastBlocks[0..partialBlockLen] ^ keyStream[0..partialBlockLen];
239 
240 			// update ghash
241 			gHash.updateCipherData(forEncryption ? output[0..partialBlockLen] : lastBlocks[0..partialBlockLen]);
242 
243 			output = output[partialBlockLen..$];
244 			outputBytes += partialBlockLen;
245 			
246 			// calculate the hash
247 			ubyte[16] mac;
248 			gHash.doFinal(mac);
249 
250 			mac[] ^= E0[]; // calculate the token
251 
252 			macBuf[0..16] = mac[];
253 
254 			return outputBytes;
255 		}
256 		
257 		/**
258 		 * return the size of the output buffer required for a processBytes
259 		 * an input of len bytes.
260 		 *
261 		 * Params: len = the length of the input.
262 		 * Returns: the space required to accommodate a call to processBytes
263 		 * with len bytes of input.
264 		 */
265 		size_t getUpdateOutputSize(size_t len) nothrow @nogc pure{
266 			size_t total = len + buf.length;
267 			//return (total + blockSize - 1) && (~blockSize+1);
268 			return total - (total % blockSize);
269 		}
270 		
271 		/**
272 		 * return the size of the output buffer required for a processBytes plus a
273 		 * doFinal with an input of len bytes.
274 		 *
275 		 * Params: len = the total length of the input.
276 		 * Returns: the space required to accommodate a call to processBytes and doFinal
277 		 * with len bytes of input.
278 		 */
279 		size_t getOutputSize(size_t len) nothrow @nogc pure {
280 			return len;
281 		}
282 		
283 		/**
284 		 * Reset the cipher. After resetting the cipher is in the same state
285 		 * as it was after the last init (if there was one).
286 		 */
287 		void reset() nothrow 
288 		{
289 			gHash.reset();
290 			buf.reset();
291 
292 			Y = initialY;
293 			blockCipher.reset();
294 		}
295 	}
296 
297 	
298 	private nothrow @safe @nogc {
299 
300 		/**
301 		 * generates the next key stream block by incrementing the counter
302 		 * and encrypting it.
303 		 * 
304 		 * bufOff is set to 0
305 		 */
306 		void genNextKeyStreamBlock(ubyte[] buf)
307 		in {
308 			assert(buf.length == blockSize);
309 			//assert(keyStreamBufOff == BLOCKSIZE, "not yet ready to generate next block");
310 		}
311 		body {
312 			blockCipher.processBlock(Y,buf);
313 			incrCounter();
314 		}
315 
316 		/**
317 		 * encrypt or decrypt a block and write it to output
318 		 * update GHash
319 		 */
320 		void outputBlock(ubyte[] output)
321 		in {
322 			assert(output.length >= blockSize, "output buffer too short");
323 			assert(buf.length >= blockSize, "not enough data in buffer");
324 		}
325 		body {
326 			ubyte[blockSize] keyStream;
327 			ubyte[blockSize] inputBuf;
328 			genNextKeyStreamBlock(keyStream);
329 
330 			buf.drainBlock(inputBuf);
331 
332 			// encrypt the buffer
333 			output[0..blockSize] = keyStream[0..blockSize] ^ inputBuf[0..blockSize];
334 
335 			// update gHash
336 			gHash.updateCipherData(forEncryption ? output[0..blockSize] : inputBuf[0..blockSize]);
337 		}
338 
339 		/** 
340 		 * increment Y by 1
341 		 * treats rightmost 32 bits as uint, lsb on the right
342 		 */
343 		void incrCounter() {
344 			for(uint i = blockSize -1; i >= blockSize-4; --i) {
345 				if(++Y[i] != 0) {
346 					break;
347 				}
348 				// increment next element on overflow of the previous
349 			}
350 		}
351 
352 	}
353 }
354 
355 /// Test OOP API with test vectors from
356 /// http://www.ieee802.org/1/files/public/docs2011/bn-randall-test-vectors-0511-v1.pdf
357 /// section 2.2.1
358 unittest {
359 	import dcrypt.crypto.engines.aes;
360 
361 	alias const(ubyte)[] octets;
362 
363 	octets key = cast(octets)x"AD7A2BD03EAC835A6F620FDCB506B345";
364 	octets iv = cast(octets)x"12153524C0895E81B2C28465"; // 96 bits
365 
366 	GCM!AES gcm;
367 	gcm.start(true, key, iv);
368 
369 	ubyte[48] output;
370 	ubyte[] oBuf = output;
371 	size_t outLen;
372 
373 	gcm.processAADBytes(cast(octets)x"D609B1F056637A0D46DF998D88E52E00");
374 
375 	outLen = gcm.processBytes(cast(octets)x"08000F101112131415161718191A1B1C", oBuf);
376 	oBuf = oBuf[outLen..$];
377 	outLen = gcm.processBytes(cast(octets)x"1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A", oBuf);
378 	oBuf = oBuf[outLen..$];
379 
380 	outLen = gcm.processBytes(cast(octets)x"0002", oBuf);
381 	oBuf = oBuf[outLen..$];
382 
383 	gcm.processAADBytes(cast(octets)x"B2C2846512153524C0895E81");
384 	ubyte[16] mac;
385 	outLen = gcm.finish(mac, oBuf);
386 	//	import std.stdio;
387 	//	writefln("%(%x%)", output);
388 	assert(output == cast(octets)x"701AFA1CC039C0D765128A665DAB69243899BF7318CCDC81C9931DA17FBE8EDD7D17CB8B4C26FC81E3284F2B7FBA713D");
389 	assert(mac == cast(octets)x"4F8D55E7D3F06FD5A13C0C29B9D5B880");
390 }
391 
392 /// test decryption
393 /// test vectors from
394 /// http://www.ieee802.org/1/files/public/docs2011/bn-randall-test-vectors-0511-v1.pdf
395 /// section 2.2.1
396 unittest {
397 	import dcrypt.crypto.engines.aes;
398 	
399 	alias const(ubyte)[] octets;
400 	
401 	octets key = cast(octets)x"AD7A2BD03EAC835A6F620FDCB506B345";
402 	octets iv = cast(octets)x"12153524C0895E81B2C28465"; // 96 bits
403 
404 	GCM!AES gcm;
405 	gcm.start(false, key, iv);
406 	
407 	ubyte[48] output;
408 	ubyte[] oBuf = output;
409 	size_t outLen;
410 	
411 	gcm.processAADBytes(cast(octets)x"D609B1F056637A0D46DF998D88E52E00");
412 
413 	// add ciphertext
414 	outLen = gcm.processBytes(cast(octets)
415 		x"701AFA1CC039C0D765128A665DAB6924
416 	      3899BF7318CCDC81C9931DA17FBE8EDD
417 	      7D17CB8B4C26FC81E3284F2B7FBA713D", oBuf);
418 	oBuf = oBuf[outLen..$];
419 
420 	gcm.processAADBytes(cast(octets)x"B2C2846512153524C0895E81");
421 	ubyte[16] mac;
422 	outLen = gcm.finish(mac, oBuf);
423 	//		import std.stdio;
424 	//		writefln("%(%.2x%)", output);
425 	
426 	assert(output == 
427 		x"08000F101112131415161718191A1B1
428 	      C1D1E1F202122232425262728292A2B
429 	      2C2D2E2F303132333435363738393A0002");
430 
431 	assert(mac == x"4F8D55E7D3F06FD5A13C0C29B9D5B880");
432 }
433 
434 /// Test decryption with modified cipher data. An exception should be thrown beacause of wrong token.
435 /// 
436 /// test vectors from
437 /// http://www.ieee802.org/1/files/public/docs2011/bn-randall-test-vectors-0511-v1.pdf
438 /// section 2.2.1
439 unittest {
440 	import dcrypt.crypto.engines.aes;
441 	
442 	alias const(ubyte)[] octets;
443 	
444 	octets key = cast(octets)x"AD7A2BD03EAC835A6F620FDCB506B345";
445 	octets iv = cast(octets)x"12153524C0895E81B2C28465"; // 96 bits
446 	
447 	GCM!AES gcm;
448 	gcm.start(false, key, iv);
449 	
450 	ubyte[48] output;
451 	ubyte[] oBuf = output[];
452 	size_t outLen;
453 	
454 	gcm.processAADBytes(cast(octets)x"D609B1F056637A0D46DF998D88E52E00");
455 	
456 	// add ciphertext
457 	outLen = gcm.processBytes(cast(octets)
458 		x"701AFA1CC039C0D765128A665DAB6924
459 	      3899BF7318CCDC81C9931DA17FBE8EDD
460 	      7D17CB8B4C26FC81E3284F2B7FBA713D", oBuf); // 880 has been changed do EEF
461 	oBuf = oBuf[outLen..$];
462 	
463 	gcm.processAADBytes(cast(octets)x"B2C2846512153524C0895E81");
464 	ubyte[16] mac;
465 	outLen = gcm.finish(mac, oBuf);
466 	assert(mac != x"4F8D55E7D3F06FD5A13C0C29B9D5BEEF");
467 }
468 
469 /// Test decryption with altered AAD. An exception should be thrown beacause of wrong token.
470 /// 
471 /// test vectors from
472 /// http://www.ieee802.org/1/files/public/docs2011/bn-randall-test-vectors-0511-v1.pdf
473 /// section 2.2.1
474 unittest {
475 	import dcrypt.crypto.engines.aes;
476 	
477 	alias const(ubyte)[] octets;
478 	
479 	octets key = cast(octets)x"AD7A2BD03EAC835A6F620FDCB506B345";
480 	octets iv = cast(octets)x"12153524C0895E81B2C28465"; // 96 bits
481 	
482 	GCM!AES gcm;
483 	gcm.start(false, key, iv);
484 	
485 	ubyte[48] output;
486 	ubyte[] oBuf = output;
487 	size_t outLen;
488 	
489 	gcm.processAADBytes(cast(octets)x"D609B1F056637A0D46DF998D88E52E00");
490 	
491 	// add ciphertext
492 	outLen = gcm.processBytes(cast(octets)
493 		x"701AFA1CC039C0D765128A665DAB6924
494 	      3899BF7318CCDC81C9931DA17FBE8EDD
495 	      7D17CB8B4C26FC81E3284F2B7FBA713D", oBuf);
496 	oBuf = oBuf[outLen..$];
497 	
498 	gcm.processAADBytes(cast(octets)x"B2C2846512153524C089beef"); // changed 5E81 to beef
499 	ubyte[16] mac;
500 	gcm.finish(mac, oBuf);
501 	assert(mac != x"4F8D55E7D3F06FD5A13C0C29B9D5B880");
502 	// verify that an InvalidCipherTextException is thrown
503 //	bool exception = false;
504 //	try {
505 //		outLen = gcm.finish(oBuf);
506 //	} catch (InvalidCipherTextException e) {
507 //		exception = true;
508 //	}
509 //	assert(exception, "AAD has been altered but no exception has been thrown!");
510 }
511 
512 // test vectors from
513 // gcm-spec: Test Case 6
514 unittest {
515 
516 	import dcrypt.crypto.engines.aes;
517 	
518 	alias const(ubyte)[] octets;
519 	
520 	octets key = cast(octets)x"feffe9928665731c6d6a8f9467308308";
521 	octets iv = cast(octets)
522 		x"9313225df88406e555909c5aff5269aa
523           6a7a9538534f7da1e4c303d2a318a728
524           c3c0c95156809539fcf0e2429a6b5254
525 	      16aedbf5a0de6a57a637b39b"; // more than 96 bits
526 
527 	GCM!AES gcm;
528 	gcm.start(true, key, iv);
529 	
530 	octets aad = cast(octets)(
531 		x"feedfacedeadbeeffeedfacedeadbeef
532           abaddad2"
533 		);
534 
535 	octets plaintext = cast(octets)(
536 		x"d9313225f88406e5a55909c5aff5269a
537           86a7a9531534f7da2e4c303d8a318a72
538           1c3c0c95956809532fcf0e2449a6b525
539           b16aedf5aa0de657ba637b39"
540 		);
541 
542 	ubyte[] output = new ubyte[gcm.getOutputSize(plaintext.length)];
543 	ubyte[] oBuf = output;
544 	size_t outLen;
545 
546 	outLen = gcm.processBytes(plaintext, oBuf);
547 	oBuf = oBuf[outLen..$];
548 
549 	gcm.processAADBytes(aad);
550 	ubyte[16] mac;
551 	outLen = gcm.finish(mac, oBuf);
552 	oBuf = oBuf[outLen..$];
553 
554 	octets expectedCiphertext = cast(octets) (
555 		x"8ce24998625615b603a033aca13fb894
556           be9112a5c3a211a8ba262a3cca7e2ca7
557           01e4a9a4fba43c90ccdcb281d48c7c6f
558           d62875d2aca417034c34aee5"
559 		);
560 
561 	octets expectedMac = cast(octets) x"619cc5aefffe0bfa462af43c1699d050";
562 	
563 	assert(output == expectedCiphertext);
564 	assert(mac == expectedMac);
565 }
566 
567 /// test GCM with different MAC sizes
568 unittest { 
569 
570 	import dcrypt.crypto.engines.aes;
571 
572 	string[] keys = [
573 		"00000000000000000000000000000000",
574 		"00000000000000000000000000000000",
575 		"00000000000000000000000000000000",
576 		"00000000000000000000000000000000",
577 		"00000000000000000000000000000000",
578 		"00000000000000000000000000000000",
579 		"00000000000000000000000000000000",
580 		"00000000000000000000000000000000",
581 		"00000000000000000000000000000000",
582 		"00000000000000000000000000000000",
583 		"00000000000000000000000000000000",
584 		"00000000000000000000000000000000",
585 		"00000000000000000000000000000000",
586 	];
587 	string[] ivs = [
588 		"00",
589 		"00000000",
590 		"00000000000000",
591 		"00000000000000000000",
592 		"00000000000000000000000000",
593 		"00000000000000000000000000000000",
594 		"00000000000000000000000000000000000000",
595 		"00000000000000000000000000000000000000000000",
596 		"00000000000000000000000000000000000000000000000000",
597 		"00000000000000000000000000000000000000000000000000000000",
598 		"00000000000000000000000000000000000000000000000000000000000000",
599 		"00000000000000000000000000000000000000000000000000000000000000000000",
600 		"00000000000000000000000000000000000000000000000000000000000000000000000000",
601 	];
602 	string[] aads = [
603 		"",
604 		"00000000000000",
605 		"0000000000000000000000000000",
606 		"000000000000000000000000000000000000000000",
607 		"00000000000000000000000000000000000000000000000000000000",
608 		"0000000000000000000000000000000000000000000000000000000000000000000000",
609 		"000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
610 		"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
611 		"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
612 		"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
613 		"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
614 		"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
615 		"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
616 	];
617 	string[] plains = [
618 		"",
619 		"0000000000",
620 		"00000000000000000000",
621 		"000000000000000000000000000000",
622 		"0000000000000000000000000000000000000000",
623 		"00000000000000000000000000000000000000000000000000",
624 		"000000000000000000000000000000000000000000000000000000000000",
625 		"0000000000000000000000000000000000000000000000000000000000000000000000",
626 		"00000000000000000000000000000000000000000000000000000000000000000000000000000000",
627 		"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
628 		"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
629 		"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
630 		"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
631 	];
632 	string[] ciphers = [
633 		"3c2fa7a9",
634 		"078bb038e6b2353f0e05",
635 		"d6a480d4dec719bd36a60efde3aaf1f8",
636 		"e37dd3785cc7017f206df18d831e37cfe63f9e057a23",
637 		"3fe95bef64662ddcf19a96cc584d2146499320eef8d518bb5e7e49a7",
638 		"a3b22b8449afafbcd6c09f2cfa9de2be938f8bbf235863d0cefb4075046c9a4d351e",
639 		"a0912f3bde077afa3f21725fbcae1c9c2e00b28b6eb462745e9b65a026cc4ba84d13b408b7061fe1",
640 		"535b0d13cbb1012df5402f748cea5304d52db1e4b997317a54c2296b95e0300c6692f911625bfe617d16b63a237b",
641 		"547096f9d7a83ba8d128467baac4a9d861ebd51cc2dfff111915cd0b4260b7dc49c8d8723eb15429024ac21eed99ca1338844092",
642 		"95e67a9eade034290efa90e33f51710f02f3aba4c32873545891924aa52dcc092695e983b529b60e7b13aee5f7d6de278c77410e216d0fdbd7e1",
643 		"0957e69831df479e8cf7b214e1cef4d3e7a2716e8179deaf8061383f35eeabd017080c3d7972b98009a38b5842a2a08a9123412338e16de05a72b76849629b48",
644 		"07052b0f8b95c9491ae43bac6693802384688e9dd19d9ce295b4ab550163a2bb4b0dd905012a56094e895ea7a5857f8100af40b4adb6452d0b8e78e709c5c9f1d432b5f59317",
645 		"e0902e27a95867acaa788920ac71b2f2a61863bdc40ee869bea53470edf02fc71800465c550a58ba69220c67243899d756cf0a5ac4fda582fc6e9d2f8498a0e73e0e809bfb8d86ab5fdf066c",
646 	];
647 	uint[] macSizes = [
648 		32,
649 		40,
650 		48,
651 		56,
652 		64,
653 		72,
654 		80,
655 		88,
656 		96,
657 		104,
658 		112,
659 		120,
660 		128,
661 	];
662 
663 	AEADCipherTest(
664 		new GCMCipher(new AESEngine()), 
665 		keys,
666 		ivs,
667 		plains,
668 		aads,
669 		ciphers,
670 		macSizes);
671 
672 }
673 
674 /// OOP Wrapper for GCM
675 @safe
676 public class GCMCipher: AEADCipher {
677 
678 	private GCM!void cipher = void;
679 	
680 	public {
681 		
682 		/// Params: c = underlying block cipher
683 		this(BlockCipher c) {
684 			cipher = GCM!void(c);
685 		}
686 		
687 		/**
688 		 * initialize the underlying cipher..
689 		 * Params:
690 		 * forEncryption = true if we are setting up for encryption, false otherwise.
691 		 * key = Secret key.
692 		 * iv = None.
693 		 * macSize = Size of mac tag in bits.
694 		 */
695 		void start(bool forEncryption, in ubyte[] key, in ubyte[] iv) nothrow @nogc {
696 			cipher.start(forEncryption, key, iv);
697 		}
698 		
699 		/**
700 		 * Return the name of the algorithm.
701 		 * 
702 		 * Returns: the algorithm name.
703 		 */
704 		@property
705 		string name() pure nothrow {
706 			return cipher.name;
707 		}
708 		
709 		/**
710 		 * return the cipher this object wraps.
711 		 *
712 		 * Returns: the cipher this object wraps.
713 		 */
714 		BlockCipher getUnderlyingCipher() pure nothrow {
715 			return cipher.getUnderlyingCipher();
716 		}
717 		
718 		
719 		/**
720 		 * Add a sequence of bytes to the associated data check.
721 		 * If the implementation supports it, this will be an online operation and will not retain the associated data.
722 		 *
723 		 * Params: in = the input byte array.
724 		 */
725 		void processAADBytes(in ubyte[] aad) nothrow {
726 			cipher.processAADBytes(aad);
727 		}
728 		
729 		/**
730 		 * process a block of bytes from in putting the result into out.
731 		 * Params:
732 		 * in = the input byte array.
733 		 * out = the output buffer the processed bytes go into.
734 		 * Returns: the number of bytes written to out.
735 		 * Throws: Error if the output buffer is too small.
736 		 */
737 		size_t processBytes(in ubyte[] input, ubyte[] output) nothrow {
738 			return cipher.processBytes(input, output);
739 		}
740 		
741 		/**
742 		 * Finish the operation either appending or verifying the MAC at the end of the data.
743 		 *
744 		 * Params:
745 		 * out = space for any resulting output data.
746 		 * macBuf = Buffer for MAC tag.
747 		 * Returns: number of bytes written into out.
748 		 * Throws: IllegalStateError = if the cipher is in an inappropriate state.
749 		 * dcrypt.exceptions.InvalidCipherTextException =  if the MAC fails to match.
750 		 */
751 		size_t doFinal(ubyte[] macBuf, ubyte[] output) {
752 			return cipher.finish(macBuf, output);
753 		}
754 		
755 		/**
756 		 * return the size of the output buffer required for a processBytes
757 		 * an input of len bytes.
758 		 *
759 		 * Params: len = the length of the input.
760 		 * Returns: the space required to accommodate a call to processBytes
761 		 * with len bytes of input.
762 		 */
763 		size_t getUpdateOutputSize(size_t len) nothrow {
764 			return cipher.getUpdateOutputSize(len);
765 		}
766 		
767 		/**
768 		 * return the size of the output buffer required for a processBytes plus a
769 		 * doFinal with an input of len bytes.
770 		 *
771 		 * Params:
772 		 * len = the length of the input.
773 		 * Returns: the space required to accommodate a call to processBytes and doFinal
774 		 * with len bytes of input.
775 		 */
776 		size_t getOutputSize(size_t len) nothrow {
777 			return cipher.getOutputSize(len);
778 		}
779 		
780 		/**
781 		 * Reset the cipher. After resetting the cipher is in the same state
782 		 * as it was after the last init (if there was one).
783 		 */
784 		void reset() nothrow {
785 			cipher.reset();
786 		}
787 	}
788 
789 }
790 
791 /**
792  * circular buffer holding 2*BLOCKSIZE bytes of data
793  */
794 @safe
795 private struct CircularBlockBuffer(size_t BLOCKSIZE) {
796 
797 	import std.algorithm: min;
798 
799 	private {
800 		ubyte[2*BLOCKSIZE] buf;
801 		size_t offset = 0;
802 		size_t contentLen = 0;
803 		ubyte nextOutputBlock = 0;
804 	}
805 
806 	invariant {
807 		assert(offset <= 2*BLOCKSIZE, "offset out of bounds");
808 		assert(contentLen <= 2*BLOCKSIZE, "contentLen out of bounds");
809 		assert(nextOutputBlock <= 2, "nextOutputBlock out of bounds");
810 	}
811 
812 	
813 	public nothrow @nogc  {
814 
815 		/**
816 		 * try to fill the buffer
817 		 * 
818 		 * Returns: number of bytes written to buffer
819 		 */
820 		size_t put(in ubyte[] input)
821 		out (result){
822 			assert(result <= input.length);
823 		}
824 		body {
825 
826 			size_t procLen = min(input.length, 2*BLOCKSIZE - contentLen);
827 
828 			const(ubyte)[] iBuf = input;
829 
830 			// copy input into buffer
831 			foreach(i;0..procLen) {
832 				buf[offset] = input[i];
833 				offset = (offset + 1) % (2*BLOCKSIZE);
834 			}
835 
836 			contentLen += procLen;
837 
838 			return procLen;
839 		}
840 
841 		bool isFull() {
842 			return contentLen == buf.length;
843 		}
844 
845 		/**
846 		 * write max one block to output if buffer is full
847 		 * 
848 		 * Returns: number of bytes written to output
849 		 */
850 		size_t drainBlock(ubyte[] output)
851 		in {
852 			assert(output.length >= BLOCKSIZE, "output buffer too short");
853 		}
854 		body {
855 			if(isFull()) {
856 
857 				size_t blockOff = nextOutputBlock * BLOCKSIZE;
858 
859 				// copy one block to output
860 				output[0..BLOCKSIZE] = buf[blockOff..blockOff+BLOCKSIZE];
861 
862 				nextOutputBlock ^= 0x01; // 0,1,0,1,...
863 				contentLen -= BLOCKSIZE;
864 				return BLOCKSIZE;
865 			}
866 
867 			return 0;
868 		}
869 
870 		/**
871 		 * write whole buffer content to output
872 		 * 
873 		 * Returns: number of bytes written to output
874 		 */
875 		size_t drainAll(ubyte[] output)
876 		in {
877 			assert(output.length >= contentLen, "output buffer too short");
878 		}
879 		body {
880 
881 			size_t startOff = nextOutputBlock * BLOCKSIZE;
882 
883 			// copy data to output
884 			foreach(i;0..contentLen) {
885 				output[i] = buf[(startOff + i) % (2*BLOCKSIZE)];
886 			}
887 
888 			size_t outLen = contentLen;
889 			contentLen = 0;
890 			nextOutputBlock = 0;
891 			offset = 0;
892 			return outLen;
893 		}
894 
895 		@property
896 		size_t length() {
897 			return contentLen;
898 		}
899 
900 		void reset() {
901 			buf[] = 0;
902 			offset = 0;
903 			contentLen = 0;
904 			nextOutputBlock = 0;
905 		}
906 		
907 	}
908 
909 	
910 }