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 }