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