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