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