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