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.util.digest.Md2;
17 
18 public  import tango.util.digest.Digest;
19 
20 private import tango.util.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         override 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 (const(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 __gshared immutable 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 debug(UnitTest)
237 {
238         unittest 
239         {
240         __gshared immutable immutable(char)[][] strings = 
241         [
242                 "",
243                 "a",
244                 "abc",
245                 "message digest",
246                 "abcdefghijklmnopqrstuvwxyz",
247                 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
248                 "12345678901234567890123456789012345678901234567890123456789012345678901234567890"
249         ];
250 
251         __gshared immutable immutable(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, immutable(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