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 }