1 /*******************************************************************************
2
3 This module implements the Ripemd128 algorithm by Hans Dobbertin,
4 Antoon Bosselaers and Bart Preneel.
5
6 See http://homes.esat.kuleuven.be/~bosselae/ripemd160.html for more
7 information.
8
9 The implementation is based on:
10 RIPEMD-160 software written by Antoon Bosselaers,
11 available at http://www.esat.kuleuven.ac.be/~cosicart/ps/AB-9601/
12
13 Copyright:
14 Copyright (c) 2009 Tango contributors.
15 Some parts copyright (c) 2009-2016 dunnhumby Germany GmbH.
16 All rights reserved.
17
18 License:
19 Tango Dual License: 3-Clause BSD License / Academic Free License v3.0.
20 See LICENSE_TANGO.txt for details.
21
22 Version: Initial release: Sep 2009
23
24 Authors: Kai Nacke
25
26 *******************************************************************************/
27
28 module ocean.util.digest.Ripemd128;
29
30 import ocean.meta.types.Qualifiers;
31
32 import ocean.util.digest.MerkleDamgard;
33
34 public import ocean.util.digest.Digest;
35
36 version (unittest) import ocean.core.Test;
37
38 /*******************************************************************************
39
40 *******************************************************************************/
41
42 final class Ripemd128 : MerkleDamgard
43 {
44 private uint[4] context;
45 private static immutable uint padChar = 0x80;
46
47 /***********************************************************************
48
49 ***********************************************************************/
50
51 private static const(uint[4]) initial =
52 [
53 0x67452301,
54 0xefcdab89,
55 0x98badcfe,
56 0x10325476
57 ];
58
59 /***********************************************************************
60
61 Construct a Ripemd128
62
63 ***********************************************************************/
64
65 this() { }
66
67 /***********************************************************************
68
69 The size of a Ripemd128 digest is 16 bytes
70
71 ***********************************************************************/
72
73 override uint digestSize() {return 16;}
74
75
76 /***********************************************************************
77
78 Initialize the cipher
79
80 Remarks:
81 Returns the cipher state to it's initial value
82
83 ***********************************************************************/
84
85 override void reset()
86 {
87 super.reset();
88 context[] = initial[];
89 }
90
91 /***********************************************************************
92
93 Obtain the digest
94
95 Returns:
96 the digest
97
98 Remarks:
99 Returns a digest of the current cipher state, this may be the
100 final digest, or a digest of the state between calls to update()
101
102 ***********************************************************************/
103
104 override void createDigest(ubyte[] buf)
105 {
106 version (BigEndian)
107 ByteSwap.swap32 (context.ptr, context.length * uint.sizeof);
108
109 buf[] = cast(ubyte[]) context;
110 }
111
112
113 /***********************************************************************
114
115 block size
116
117 Returns:
118 the block size
119
120 Remarks:
121 Specifies the size (in bytes) of the block of data to pass to
122 each call to transform(). For Ripemd128 the blockSize is 64.
123
124 ***********************************************************************/
125
126 protected override uint blockSize() { return 64; }
127
128 /***********************************************************************
129
130 Length padding size
131
132 Returns:
133 the length padding size
134
135 Remarks:
136 Specifies the size (in bytes) of the padding which uses the
137 length of the data which has been ciphered, this padding is
138 carried out by the padLength method. For Ripemd128 the addSize is 8.
139
140 ***********************************************************************/
141
142 protected override uint addSize() { return 8; }
143
144 /***********************************************************************
145
146 Pads the cipher data
147
148 Params:
149 at = a slice of the cipher buffer to fill with padding
150
151 Remarks:
152 Fills the passed buffer slice with the appropriate padding for
153 the final call to transform(). This padding will fill the cipher
154 buffer up to blockSize()-addSize().
155
156 ***********************************************************************/
157
158 protected override void padMessage(ubyte[] at)
159 {
160 at[0] = padChar;
161 at[1..at.length] = 0;
162 }
163
164 /***********************************************************************
165
166 Performs the length padding
167
168 Params:
169 at = the slice of the cipher buffer to fill with padding
170 length = the length of the data which has been ciphered
171
172 Remarks:
173 Fills the passed buffer slice with addSize() bytes of padding
174 based on the length in bytes of the input data which has been
175 ciphered.
176
177 ***********************************************************************/
178
179 protected override void padLength(ubyte[] at, ulong length)
180 {
181 length <<= 3;
182 littleEndian64((cast(ubyte*)&length)[0..8],cast(ulong[]) at);
183 }
184
185 /***********************************************************************
186
187 Performs the cipher on a block of data
188
189 Params:
190 input = the block of data to cipher
191
192 Remarks:
193 The actual cipher algorithm is carried out by this method on
194 the passed block of data. This method is called for every
195 blockSize() bytes of input data and once more with the remaining
196 data padded to blockSize().
197
198 ***********************************************************************/
199
200 protected override void transform(ubyte[] input)
201 {
202 uint al, bl, cl, dl;
203 uint ar, br, cr, dr;
204 uint[16] x;
205
206 littleEndian32(input,x);
207
208 al = ar = context[0];
209 bl = br = context[1];
210 cl = cr = context[2];
211 dl = dr = context[3];
212
213 // Round 1 and parallel round 1
214 al = rotateLeft(al + (bl ^ cl ^ dl) + x[0], 11);
215 ar = rotateLeft(ar + ((br & dr) | (cr & ~(dr))) + x[5] + 0x50a28be6, 8);
216 dl = rotateLeft(dl + (al ^ bl ^ cl) + x[1], 14);
217 dr = rotateLeft(dr + ((ar & cr) | (br & ~(cr))) + x[14] + 0x50a28be6, 9);
218 cl = rotateLeft(cl + (dl ^ al ^ bl) + x[2], 15);
219 cr = rotateLeft(cr + ((dr & br) | (ar & ~(br))) + x[7] + 0x50a28be6, 9);
220 bl = rotateLeft(bl + (cl ^ dl ^ al) + x[3], 12);
221 br = rotateLeft(br + ((cr & ar) | (dr & ~(ar))) + x[0] + 0x50a28be6, 11);
222 al = rotateLeft(al + (bl ^ cl ^ dl) + x[4], 5);
223 ar = rotateLeft(ar + ((br & dr) | (cr & ~(dr))) + x[9] + 0x50a28be6, 13);
224 dl = rotateLeft(dl + (al ^ bl ^ cl) + x[5], 8);
225 dr = rotateLeft(dr + ((ar & cr) | (br & ~(cr))) + x[2] + 0x50a28be6, 15);
226 cl = rotateLeft(cl + (dl ^ al ^ bl) + x[6], 7);
227 cr = rotateLeft(cr + ((dr & br) | (ar & ~(br))) + x[11] + 0x50a28be6, 15);
228 bl = rotateLeft(bl + (cl ^ dl ^ al) + x[7], 9);
229 br = rotateLeft(br + ((cr & ar) | (dr & ~(ar))) + x[4] + 0x50a28be6, 5);
230 al = rotateLeft(al + (bl ^ cl ^ dl) + x[8], 11);
231 ar = rotateLeft(ar + ((br & dr) | (cr & ~(dr))) + x[13] + 0x50a28be6, 7);
232 dl = rotateLeft(dl + (al ^ bl ^ cl) + x[9], 13);
233 dr = rotateLeft(dr + ((ar & cr) | (br & ~(cr))) + x[6] + 0x50a28be6, 7);
234 cl = rotateLeft(cl + (dl ^ al ^ bl) + x[10], 14);
235 cr = rotateLeft(cr + ((dr & br) | (ar & ~(br))) + x[15] + 0x50a28be6, 8);
236 bl = rotateLeft(bl + (cl ^ dl ^ al) + x[11], 15);
237 br = rotateLeft(br + ((cr & ar) | (dr & ~(ar))) + x[8] + 0x50a28be6, 11);
238 al = rotateLeft(al + (bl ^ cl ^ dl) + x[12], 6);
239 ar = rotateLeft(ar + ((br & dr) | (cr & ~(dr))) + x[1] + 0x50a28be6, 14);
240 dl = rotateLeft(dl + (al ^ bl ^ cl) + x[13], 7);
241 dr = rotateLeft(dr + ((ar & cr) | (br & ~(cr))) + x[10] + 0x50a28be6, 14);
242 cl = rotateLeft(cl + (dl ^ al ^ bl) + x[14], 9);
243 cr = rotateLeft(cr + ((dr & br) | (ar & ~(br))) + x[3] + 0x50a28be6, 12);
244 bl = rotateLeft(bl + (cl ^ dl ^ al) + x[15], 8);
245 br = rotateLeft(br + ((cr & ar) | (dr & ~(ar))) + x[12] + 0x50a28be6, 6);
246
247 // Round 2 and parallel round 2
248 al = rotateLeft(al + (((cl ^ dl) & bl) ^ dl) + x[7] + 0x5a827999, 7);
249 ar = rotateLeft(ar + ((br | ~(cr)) ^ dr) + x[6] + 0x5c4dd124, 9);
250 dl = rotateLeft(dl + (((bl ^ cl) & al) ^ cl) + x[4] + 0x5a827999, 6);
251 dr = rotateLeft(dr + ((ar | ~(br)) ^ cr) + x[11] + 0x5c4dd124, 13);
252 cl = rotateLeft(cl + (((al ^ bl) & dl) ^ bl) + x[13] + 0x5a827999, 8);
253 cr = rotateLeft(cr + ((dr | ~(ar)) ^ br) + x[3] + 0x5c4dd124, 15);
254 bl = rotateLeft(bl + (((dl ^ al) & cl) ^ al) + x[1] + 0x5a827999, 13);
255 br = rotateLeft(br + ((cr | ~(dr)) ^ ar) + x[7] + 0x5c4dd124, 7);
256 al = rotateLeft(al + (((cl ^ dl) & bl) ^ dl) + x[10] + 0x5a827999, 11);
257 ar = rotateLeft(ar + ((br | ~(cr)) ^ dr) + x[0] + 0x5c4dd124, 12);
258 dl = rotateLeft(dl + (((bl ^ cl) & al) ^ cl) + x[6] + 0x5a827999, 9);
259 dr = rotateLeft(dr + ((ar | ~(br)) ^ cr) + x[13] + 0x5c4dd124, 8);
260 cl = rotateLeft(cl + (((al ^ bl) & dl) ^ bl) + x[15] + 0x5a827999, 7);
261 cr = rotateLeft(cr + ((dr | ~(ar)) ^ br) + x[5] + 0x5c4dd124, 9);
262 bl = rotateLeft(bl + (((dl ^ al) & cl) ^ al) + x[3] + 0x5a827999, 15);
263 br = rotateLeft(br + ((cr | ~(dr)) ^ ar) + x[10] + 0x5c4dd124, 11);
264 al = rotateLeft(al + (((cl ^ dl) & bl) ^ dl) + x[12] + 0x5a827999, 7);
265 ar = rotateLeft(ar + ((br | ~(cr)) ^ dr) + x[14] + 0x5c4dd124, 7);
266 dl = rotateLeft(dl + (((bl ^ cl) & al) ^ cl) + x[0] + 0x5a827999, 12);
267 dr = rotateLeft(dr + ((ar | ~(br)) ^ cr) + x[15] + 0x5c4dd124, 7);
268 cl = rotateLeft(cl + (((al ^ bl) & dl) ^ bl) + x[9] + 0x5a827999, 15);
269 cr = rotateLeft(cr + ((dr | ~(ar)) ^ br) + x[8] + 0x5c4dd124, 12);
270 bl = rotateLeft(bl + (((dl ^ al) & cl) ^ al) + x[5] + 0x5a827999, 9);
271 br = rotateLeft(br + ((cr | ~(dr)) ^ ar) + x[12] + 0x5c4dd124, 7);
272 al = rotateLeft(al + (((cl ^ dl) & bl) ^ dl) + x[2] + 0x5a827999, 11);
273 ar = rotateLeft(ar + ((br | ~(cr)) ^ dr) + x[4] + 0x5c4dd124, 6);
274 dl = rotateLeft(dl + (((bl ^ cl) & al) ^ cl) + x[14] + 0x5a827999, 7);
275 dr = rotateLeft(dr + ((ar | ~(br)) ^ cr) + x[9] + 0x5c4dd124, 15);
276 cl = rotateLeft(cl + (((al ^ bl) & dl) ^ bl) + x[11] + 0x5a827999, 13);
277 cr = rotateLeft(cr + ((dr | ~(ar)) ^ br) + x[1] + 0x5c4dd124, 13);
278 bl = rotateLeft(bl + (((dl ^ al) & cl) ^ al) + x[8] + 0x5a827999, 12);
279 br = rotateLeft(br + ((cr | ~(dr)) ^ ar) + x[2] + 0x5c4dd124, 11);
280
281 // Round 3 and parallel round 3
282 al = rotateLeft(al + ((bl | ~(cl)) ^ dl) + x[3] + 0x6ed9eba1, 11);
283 ar = rotateLeft(ar + (((cr ^ dr) & br) ^ dr) + x[15] + 0x6d703ef3, 9);
284 dl = rotateLeft(dl + ((al | ~(bl)) ^ cl) + x[10] + 0x6ed9eba1, 13);
285 dr = rotateLeft(dr + (((br ^ cr) & ar) ^ cr) + x[5] + 0x6d703ef3, 7);
286 cl = rotateLeft(cl + ((dl | ~(al)) ^ bl) + x[14] + 0x6ed9eba1, 6);
287 cr = rotateLeft(cr + (((ar ^ br) & dr) ^ br) + x[1] + 0x6d703ef3, 15);
288 bl = rotateLeft(bl + ((cl | ~(dl)) ^ al) + x[4] + 0x6ed9eba1, 7);
289 br = rotateLeft(br + (((dr ^ ar) & cr) ^ ar) + x[3] + 0x6d703ef3, 11);
290 al = rotateLeft(al + ((bl | ~(cl)) ^ dl) + x[9] + 0x6ed9eba1, 14);
291 ar = rotateLeft(ar + (((cr ^ dr) & br) ^ dr) + x[7] + 0x6d703ef3, 8);
292 dl = rotateLeft(dl + ((al | ~(bl)) ^ cl) + x[15] + 0x6ed9eba1, 9);
293 dr = rotateLeft(dr + (((br ^ cr) & ar) ^ cr) + x[14] + 0x6d703ef3, 6);
294 cl = rotateLeft(cl + ((dl | ~(al)) ^ bl) + x[8] + 0x6ed9eba1, 13);
295 cr = rotateLeft(cr + (((ar ^ br) & dr) ^ br) + x[6] + 0x6d703ef3, 6);
296 bl = rotateLeft(bl + ((cl | ~(dl)) ^ al) + x[1] + 0x6ed9eba1, 15);
297 br = rotateLeft(br + (((dr ^ ar) & cr) ^ ar) + x[9] + 0x6d703ef3, 14);
298 al = rotateLeft(al + ((bl | ~(cl)) ^ dl) + x[2] + 0x6ed9eba1, 14);
299 ar = rotateLeft(ar + (((cr ^ dr) & br) ^ dr) + x[11] + 0x6d703ef3, 12);
300 dl = rotateLeft(dl + ((al | ~(bl)) ^ cl) + x[7] + 0x6ed9eba1, 8);
301 dr = rotateLeft(dr + (((br ^ cr) & ar) ^ cr) + x[8] + 0x6d703ef3, 13);
302 cl = rotateLeft(cl + ((dl | ~(al)) ^ bl) + x[0] + 0x6ed9eba1, 13);
303 cr = rotateLeft(cr + (((ar ^ br) & dr) ^ br) + x[12] + 0x6d703ef3, 5);
304 bl = rotateLeft(bl + ((cl | ~(dl)) ^ al) + x[6] + 0x6ed9eba1, 6);
305 br = rotateLeft(br + (((dr ^ ar) & cr) ^ ar) + x[2] + 0x6d703ef3, 14);
306 al = rotateLeft(al + ((bl | ~(cl)) ^ dl) + x[13] + 0x6ed9eba1, 5);
307 ar = rotateLeft(ar + (((cr ^ dr) & br) ^ dr) + x[10] + 0x6d703ef3, 13);
308 dl = rotateLeft(dl + ((al | ~(bl)) ^ cl) + x[11] + 0x6ed9eba1, 12);
309 dr = rotateLeft(dr + (((br ^ cr) & ar) ^ cr) + x[0] + 0x6d703ef3, 13);
310 cl = rotateLeft(cl + ((dl | ~(al)) ^ bl) + x[5] + 0x6ed9eba1, 7);
311 cr = rotateLeft(cr + (((ar ^ br) & dr) ^ br) + x[4] + 0x6d703ef3, 7);
312 bl = rotateLeft(bl + ((cl | ~(dl)) ^ al) + x[12] + 0x6ed9eba1, 5);
313 br = rotateLeft(br + (((dr ^ ar) & cr) ^ ar) + x[13] + 0x6d703ef3, 5);
314
315 // Round 4 and parallel round 4
316 al = rotateLeft(al + ((bl & dl) | (cl & ~(dl))) + x[1] + 0x8f1bbcdc, 11);
317 ar = rotateLeft(ar + (br ^ cr ^ dr) + x[8], 15);
318 dl = rotateLeft(dl + ((al & cl) | (bl & ~(cl))) + x[9] + 0x8f1bbcdc, 12);
319 dr = rotateLeft(dr + (ar ^ br ^ cr) + x[6], 5);
320 cl = rotateLeft(cl + ((dl & bl) | (al & ~(bl))) + x[11] + 0x8f1bbcdc, 14);
321 cr = rotateLeft(cr + (dr ^ ar ^ br) + x[4], 8);
322 bl = rotateLeft(bl + ((cl & al) | (dl & ~(al))) + x[10] + 0x8f1bbcdc, 15);
323 br = rotateLeft(br + (cr ^ dr ^ ar) + x[1], 11);
324 al = rotateLeft(al + ((bl & dl) | (cl & ~(dl))) + x[0] + 0x8f1bbcdc, 14);
325 ar = rotateLeft(ar + (br ^ cr ^ dr) + x[3], 14);
326 dl = rotateLeft(dl + ((al & cl) | (bl & ~(cl))) + x[8] + 0x8f1bbcdc, 15);
327 dr = rotateLeft(dr + (ar ^ br ^ cr) + x[11], 14);
328 cl = rotateLeft(cl + ((dl & bl) | (al & ~(bl))) + x[12] + 0x8f1bbcdc, 9);
329 cr = rotateLeft(cr + (dr ^ ar ^ br) + x[15], 6);
330 bl = rotateLeft(bl + ((cl & al) | (dl & ~(al))) + x[4] + 0x8f1bbcdc, 8);
331 br = rotateLeft(br + (cr ^ dr ^ ar) + x[0], 14);
332 al = rotateLeft(al + ((bl & dl) | (cl & ~(dl))) + x[13] + 0x8f1bbcdc, 9);
333 ar = rotateLeft(ar + (br ^ cr ^ dr) + x[5], 6);
334 dl = rotateLeft(dl + ((al & cl) | (bl & ~(cl))) + x[3] + 0x8f1bbcdc, 14);
335 dr = rotateLeft(dr + (ar ^ br ^ cr) + x[12], 9);
336 cl = rotateLeft(cl + ((dl & bl) | (al & ~(bl))) + x[7] + 0x8f1bbcdc, 5);
337 cr = rotateLeft(cr + (dr ^ ar ^ br) + x[2], 12);
338 bl = rotateLeft(bl + ((cl & al) | (dl & ~(al))) + x[15] + 0x8f1bbcdc, 6);
339 br = rotateLeft(br + (cr ^ dr ^ ar) + x[13], 9);
340 al = rotateLeft(al + ((bl & dl) | (cl & ~(dl))) + x[14] + 0x8f1bbcdc, 8);
341 ar = rotateLeft(ar + (br ^ cr ^ dr) + x[9], 12);
342 dl = rotateLeft(dl + ((al & cl) | (bl & ~(cl))) + x[5] + 0x8f1bbcdc, 6);
343 dr = rotateLeft(dr + (ar ^ br ^ cr) + x[7], 5);
344 cl = rotateLeft(cl + ((dl & bl) | (al & ~(bl))) + x[6] + 0x8f1bbcdc, 5);
345 cr = rotateLeft(cr + (dr ^ ar ^ br) + x[10], 15);
346 bl = rotateLeft(bl + ((cl & al) | (dl & ~(al))) + x[2] + 0x8f1bbcdc, 12);
347 br = rotateLeft(br + (cr ^ dr ^ ar) + x[14], 8);
348
349 uint t = context[1] + cl + dr;
350 context[1] = context[2] + dl + ar;
351 context[2] = context[3] + al + br;
352 context[3] = context[0] + bl + cr;
353 context[0] = t;
354
355 x[] = 0;
356 }
357
358 }
359
360 /*******************************************************************************
361
362 *******************************************************************************/
363
364 unittest
365 {
366 static istring[] strings = [
367 "",
368 "a",
369 "abc",
370 "message digest",
371 "abcdefghijklmnopqrstuvwxyz",
372 "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
373 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
374 "12345678901234567890123456789012345678901234567890123456789012345678901234567890"
375 ];
376
377 static istring[] results = [
378 "cdf26213a150dc3ecb610f18f6b38b46",
379 "86be7afa339d0fc7cfc785e72f578d33",
380 "c14a12199c66e4ba84636b0f69144c77",
381 "9e327b3d6e523062afc1132d7df9d1b8",
382 "fd2aa607f71dc8f510714922b371834e",
383 "a1aa0689d0fafa2ddc22e88b49133a06",
384 "d1e959eb179c911faea4624c60c5c702",
385 "3f45ef194732c2dbb2c4a2c769795fa3"
386 ];
387
388 Ripemd128 h = new Ripemd128();
389
390 foreach (i, s; strings)
391 {
392 h.update(cast(ubyte[]) s);
393 char[] d = h.hexDigest;
394
395 test(d == results[i],":("~s~")("~d~")!=("~results[i]~")");
396 }
397
398 char[] s = new char[1000000];
399 for (auto i = 0; i < s.length; i++) s[i] = 'a';
400 auto result = "4a7f5723f954eba1216c9d8f6320431f";
401 h.update(cast(ubyte[]) s);
402 auto d = h.hexDigest;
403
404 test(d == result,":(1 million times \"a\")("~d~")!=("~result~")");
405 }