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 }