1 module dcrypt.macs.gmac; 2 3 public import dcrypt.macs.mac; 4 import dcrypt.aead.gcm.gcm; 5 6 7 /// Special case of GCMEngine where no data gets encrypted 8 /// but all processed as AAD. 9 /// 10 /// Standards: NIST Special Publication 800-38D 11 @safe 12 public struct GMac(T) if(isBlockCipher!T) 13 { 14 enum macSize = 16; 15 16 private { 17 GCM!T gcm; 18 bool initialized = false; 19 } 20 21 public { 22 23 enum name = "GMAC-"~T.name; 24 25 void start(in ubyte[] key, in ubyte[] nonce) { 26 gcm.start(true, key, nonce); 27 initialized = true; 28 } 29 30 /// Update the MAC with a block of bytes. 31 /// 32 /// Params: 33 /// input = The ubyte slice containing the data. 34 void put(in ubyte[] input...) nothrow @nogc 35 in { 36 assert(initialized, "GMac not initialized. call init() first."); 37 } 38 body { 39 gcm.processAADBytes(input); 40 } 41 42 /// Close the MAC, producing the final MAC value. 43 /// Leaves the MAC reset. 44 /// 45 /// Params: 46 /// output = Output buffer for MAC tag. 47 /// 48 /// Returns: Returns a slice pointing to the MAC tag in the output buffer. 49 void finish(ubyte[] output) nothrow 50 in { 51 assert(initialized, "GMac not initialized. call init() first."); 52 assert(output.length >= gcm.macSize, "output buffer too short for MAC"); 53 } 54 body { 55 56 scope(exit) { 57 reset(); 58 } 59 60 gcm.finish(output[0..macSize], output[0..0]); 61 } 62 63 /// Reset the digest back to it's initial state. 64 void reset() nothrow 65 in { 66 assert(initialized, "GMac not initialized. call init() first."); 67 } 68 body { 69 gcm.reset(); 70 } 71 } 72 } 73 74 /// simple usage of GMac 75 /// with test vectors from 76 /// http://www.ieee802.org/1/files/public/docs2011/bn-randall-test-vectors-0511-v1.pdf, section 2.1.1 77 unittest { 78 79 import dcrypt.blockcipher.aes; 80 81 alias const(ubyte)[] octets; 82 83 octets key = cast(octets)x"AD7A2BD03EAC835A6F620FDCB506B345"; 84 octets iv = cast(octets)x"12153524C0895E81B2C28465"; 85 86 auto gmac = new GMac!AES(); 87 gmac.start(key, iv); 88 89 90 octets aad = cast(octets)( 91 x"D609B1F056637A0D46DF998D88E5222A 92 B2C2846512153524C0895E8108000F10 93 1112131415161718191A1B1C1D1E1F20 94 2122232425262728292A2B2C2D2E2F30 95 313233340001" 96 ); 97 98 gmac.put(aad); 99 100 ubyte[] outbuf = new ubyte[gmac.macSize]; 101 102 gmac.finish(outbuf); 103 104 octets expectedMac = cast(octets) (x"F09478A9B09007D06F46E9B6A1DA25DD"); 105 106 assert(outbuf == expectedMac); 107 } 108