1 2 module dcrypt.crypto.macs.mac; 3 4 // TODO as output range 5 6 /// Test if T is a message authentication code (MAC). 7 template isMAC(T) 8 { 9 enum bool isMAC = 10 is(T == struct) && 11 is(typeof( 12 { 13 ubyte[] data; 14 T t = T.init; // can define 15 t.start(data); // set the mac key 16 t.reset(); // can reset the mac 17 18 t.put(cast(ubyte)0); // can add a single byte 19 t.put(data); // can add bytes 20 t.put(cast(ubyte)0, cast(ubyte)0); // has variadic put 21 22 ubyte[] slice = t.finish(data); 23 auto macTag = t.finish(); 24 25 uint macSize = T.macSize; 26 string name = T.name; 27 28 })); 29 } 30 31 /// Variadic 'put' helper function for MACs. 32 /// 33 /// Params: 34 /// mac = The mac to put the data into. 35 /// data = The data to update the mac with. 36 /// 37 /// Example: 38 /// ubyte[4] buf; 39 /// HMac!SHA256 mac; 40 /// mac.putAll(cast(ubyte) 0x01, buf, buf[0..2]); 41 @safe 42 public void putAll(M, T...)(ref M mac, in T data) nothrow @nogc 43 if(isMAC!M) { 44 foreach(d; data) { 45 mac.put(d); 46 } 47 } 48 49 50 @safe 51 public abstract class Mac { 52 53 54 55 @safe @property 56 public abstract string name() pure nothrow; 57 58 /** 59 * Returns: the size, in bytes, of the MAC. 60 */ 61 @safe @property 62 public abstract uint macSize() pure nothrow; 63 64 /** 65 * update the MAC with a block of bytes. 66 * 67 * Params: 68 * input the ubyte slice containing the data. 69 */ 70 @safe 71 public abstract void put(in ubyte[] input...) nothrow; 72 73 /** 74 * close the MAC, producing the final MAC value. The doFinal 75 * call leaves the MAC reset(). */ 76 @safe 77 public abstract size_t doFinal(ubyte[] output) nothrow; 78 79 /** 80 * close the MAC, producing the final MAC value. The doFinal 81 * call leaves the MAC reset(). */ 82 @safe 83 public final ubyte[] doFinal() nothrow { 84 ubyte[] output = new ubyte[macSize]; 85 doFinal(output); 86 return output; 87 } 88 /** 89 * reset the digest back to it's initial state. 90 */ 91 @safe 92 public abstract void reset() nothrow ; 93 94 } 95 96 @safe 97 public class WrapperMac(T) if(isMAC!T) { 98 99 private T mac; 100 101 @safe @property 102 public string name() pure nothrow { 103 return mac.name; 104 } 105 106 /** 107 * Returns: the size, in bytes, of the MAC. 108 */ 109 @safe @property 110 public uint macSize() pure nothrow { 111 return mac.macSize; 112 } 113 114 @save 115 public void start(in ubyte[] key, in ubyte[] nonce = null); 116 117 /** 118 * update the MAC with a single byte. 119 * 120 * Params: 121 * input = the input byte to be entered. 122 */ 123 @safe 124 public void put(ubyte input) nothrow { 125 mac.put(input); 126 } 127 128 /** 129 * update the MAC with a block of bytes. 130 * 131 * Params: 132 * input the ubyte slice containing the data. 133 */ 134 @safe 135 public void put(in ubyte[] input) nothrow { 136 mac.put(input); 137 } 138 139 /** 140 * close the MAC, producing the final MAC value. The doFinal 141 * call leaves the MAC reset(). */ 142 @safe 143 public size_t doFinal(ubyte[] output) nothrow { 144 return mac.doFinal(output); 145 } 146 147 /** 148 * close the MAC, producing the final MAC value. The doFinal 149 * call leaves the MAC reset(). */ 150 @safe 151 public final ubyte[] doFinal() nothrow { 152 ubyte[] output = new ubyte[macSize]; 153 doFinal(output); 154 return output; 155 } 156 /** 157 * reset the digest back to it's initial state. 158 */ 159 @safe 160 public void reset() nothrow { 161 mac.reset(); 162 } 163 164 }