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 }