132
|
1 /*******************************************************************************
|
|
2
|
|
3 copyright: Copyright (c) 2006 Tango. All rights reserved
|
|
4
|
|
5 license: BSD style: see doc/license.txt for details
|
|
6
|
|
7 version: Initial release: Feb 2006
|
|
8
|
|
9 author: Regan Heath, Oskar Linde
|
|
10
|
|
11 This module implements the MD2 Message Digest Algorithm as described
|
|
12 by RFC 1319 The MD2 Message-Digest Algorithm. B. Kaliski. April 1992.
|
|
13
|
|
14 *******************************************************************************/
|
|
15
|
|
16 module tango.io.digest.Md2;
|
|
17
|
|
18 public import tango.io.digest.Digest;
|
|
19
|
|
20 private import tango.io.digest.MerkleDamgard;
|
|
21
|
|
22 /*******************************************************************************
|
|
23
|
|
24 *******************************************************************************/
|
|
25
|
|
26 class Md2 : MerkleDamgard
|
|
27 {
|
|
28 private ubyte[16] C,
|
|
29 state;
|
|
30
|
|
31 /***********************************************************************
|
|
32
|
|
33 Construct an Md2
|
|
34
|
|
35 ***********************************************************************/
|
|
36
|
|
37 this() { }
|
|
38
|
|
39 /***********************************************************************
|
|
40
|
|
41 Initialize the cipher
|
|
42
|
|
43 Remarks:
|
|
44 Returns the cipher state to it's initial value
|
|
45
|
|
46 ***********************************************************************/
|
|
47
|
|
48 protected override void reset()
|
|
49 {
|
|
50 super.reset();
|
|
51 state[] = 0;
|
|
52 C[] = 0;
|
|
53 }
|
|
54
|
|
55 /***********************************************************************
|
|
56
|
|
57 Obtain the digest
|
|
58
|
|
59 Returns:
|
|
60 the digest
|
|
61
|
|
62 Remarks:
|
|
63 Returns a digest of the current cipher state, this may
|
|
64 be the final digest, or a digest of the state between
|
|
65 calls to update()
|
|
66
|
|
67 ***********************************************************************/
|
|
68
|
|
69 protected override void createDigest(ubyte[] buf)
|
|
70 {
|
|
71 buf[] = state;
|
|
72 }
|
|
73
|
|
74 /***********************************************************************
|
|
75
|
|
76 The MD 2 digest size is 16 bytes
|
|
77
|
|
78 ***********************************************************************/
|
|
79
|
|
80 uint digestSize() { return 16; }
|
|
81
|
|
82 /***********************************************************************
|
|
83
|
|
84 block size
|
|
85
|
|
86 Returns:
|
|
87 the block size
|
|
88
|
|
89 Remarks:
|
|
90 Specifies the size (in bytes) of the block of data to pass to
|
|
91 each call to transform(). For MD2 the blockSize is 16.
|
|
92
|
|
93 ***********************************************************************/
|
|
94
|
|
95 protected override uint blockSize()
|
|
96 {
|
|
97 return 16;
|
|
98 }
|
|
99
|
|
100 /***********************************************************************
|
|
101
|
|
102 Length padding size
|
|
103
|
|
104 Returns:
|
|
105 the length padding size
|
|
106
|
|
107 Remarks:
|
|
108 Specifies the size (in bytes) of the padding which uses the
|
|
109 length of the data which has been ciphered, this padding is
|
|
110 carried out by the padLength method. For MD2 the addSize is
|
|
111 0
|
|
112
|
|
113 ***********************************************************************/
|
|
114
|
|
115 protected override uint addSize()
|
|
116 {
|
|
117 return 0;
|
|
118 }
|
|
119
|
|
120 /***********************************************************************
|
|
121
|
|
122 Pads the cipher data
|
|
123
|
|
124 Params:
|
|
125 data = a slice of the cipher buffer to fill with padding
|
|
126
|
|
127 Remarks:
|
|
128 Fills the passed buffer slice with the appropriate padding
|
|
129 for the final call to transform(). This padding will fill
|
|
130 the cipher buffer up to blockSize()-addSize().
|
|
131
|
|
132 ***********************************************************************/
|
|
133
|
|
134 protected override void padMessage (ubyte[] data)
|
|
135 {
|
|
136 /* Padding is performed as follows: "i" bytes of value "i"
|
|
137 * are appended to the message so that the length in bytes
|
|
138 * of the padded message becomes congruent to 0, modulo 16.
|
|
139 * At least one byte and at most 16 bytes are appended.
|
|
140 */
|
|
141 data[0..$] = cast(ubyte) data.length;
|
|
142 }
|
|
143
|
|
144 /***********************************************************************
|
|
145
|
|
146 Performs the cipher on a block of data
|
|
147
|
|
148 Params:
|
|
149 data = the block of data to cipher
|
|
150
|
|
151 Remarks:
|
|
152 The actual cipher algorithm is carried out by this method on
|
|
153 the passed block of data. This method is called for every
|
|
154 blockSize() bytes of input data and once more with the
|
|
155 remaining data padded to blockSize().
|
|
156
|
|
157 ***********************************************************************/
|
|
158
|
|
159 protected override void transform (ubyte[] input)
|
|
160 {
|
|
161 ubyte[48] X;
|
|
162 uint t,i,j;
|
|
163
|
|
164 X[0..16] = state[];
|
|
165 X[16..32] = input[];
|
|
166
|
|
167 for (i = 0; i < 16; i++)
|
|
168 X[i+32] = cast(ubyte) (state[i] ^ input[i]);
|
|
169
|
|
170 t = 0;
|
|
171 for (i = 0; i < 18; i++)
|
|
172 {
|
|
173 for (j = 0; j < 48; j++)
|
|
174 t = X[j] ^= PI[t];
|
|
175 t = (t + i) & 0xff;
|
|
176 }
|
|
177
|
|
178 state[] = X[0..16];
|
|
179
|
|
180 t = C[15];
|
|
181
|
|
182 for (i = 0; i < 16; i++)
|
|
183 t = C[i] ^= PI[input[i] ^ t];
|
|
184 }
|
|
185
|
|
186 /***********************************************************************
|
|
187
|
|
188 Final processing of cipher.
|
|
189
|
|
190 Remarks:
|
|
191 This method is called after the final transform just prior to
|
|
192 the creation of the final digest. The MD2 algorithm requires
|
|
193 an additional step at this stage. Future ciphers may or may not
|
|
194 require this method.
|
|
195
|
|
196 ***********************************************************************/
|
|
197
|
|
198 protected override void extend()
|
|
199 {
|
|
200 transform(C);
|
|
201 }
|
|
202 }
|
|
203
|
|
204
|
|
205 /*******************************************************************************
|
|
206
|
|
207 *******************************************************************************/
|
|
208
|
|
209 private const ubyte[256] PI =
|
|
210 [
|
|
211 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6,
|
|
212 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188,
|
|
213 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24,
|
|
214 138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251,
|
|
215 245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63,
|
|
216 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50,
|
|
217 39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165,
|
|
218 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
|
|
219 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157,
|
|
220 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27,
|
|
221 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
|
|
222 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197,
|
|
223 234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65,
|
|
224 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123,
|
|
225 8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233,
|
|
226 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228,
|
|
227 166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237,
|
|
228 31, 26, 219, 153, 141, 51, 159, 17, 131, 20
|
|
229 ];
|
|
230
|
|
231
|
|
232 /*******************************************************************************
|
|
233
|
|
234 *******************************************************************************/
|
|
235
|
|
236 version (UnitTest)
|
|
237 {
|
|
238 unittest
|
|
239 {
|
|
240 static char[][] strings =
|
|
241 [
|
|
242 "",
|
|
243 "a",
|
|
244 "abc",
|
|
245 "message digest",
|
|
246 "abcdefghijklmnopqrstuvwxyz",
|
|
247 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
|
|
248 "12345678901234567890123456789012345678901234567890123456789012345678901234567890"
|
|
249 ];
|
|
250
|
|
251 static char[][] results =
|
|
252 [
|
|
253 "8350e5a3e24c153df2275c9f80692773",
|
|
254 "32ec01ec4a6dac72c0ab96fb34c0b5d1",
|
|
255 "da853b0d3f88d99b30283a69e6ded6bb",
|
|
256 "ab4f496bfb2a530b219ff33031fe06b0",
|
|
257 "4e8ddff3650292ab5a4108c3aa47940b",
|
|
258 "da33def2a42df13975352846c30338cd",
|
|
259 "d5976f79d83d3a0dc9806c3c66f3efd8"
|
|
260 ];
|
|
261
|
|
262 Md2 h = new Md2();
|
|
263
|
|
264 foreach (int i, char[] s; strings)
|
|
265 {
|
|
266 h.update(s);
|
|
267 char[] d = h.hexDigest();
|
|
268 assert(d == results[i],":("~s~")("~d~")!=("~results[i]~")");
|
|
269 }
|
|
270 }
|
|
271 }
|
|
272
|