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 MD4 Message Digest Algorithm as described 12 by RFC 1320 The MD4 Message-Digest Algorithm. R. Rivest. April 1992. 13 14 *******************************************************************************/ 15 16 module tango.util.digest.Md4; 17 18 public import tango.util.digest.Digest; 19 20 private import tango.util.digest.MerkleDamgard; 21 22 /******************************************************************************* 23 24 *******************************************************************************/ 25 26 class Md4 : MerkleDamgard 27 { 28 protected uint[4] context; 29 private enum ubyte padChar = 0x80; 30 31 /*********************************************************************** 32 33 Construct an Md4 34 35 ***********************************************************************/ 36 37 this() { } 38 39 /*********************************************************************** 40 41 The MD 4 digest size is 16 bytes 42 43 ***********************************************************************/ 44 45 override uint digestSize() { return 16; } 46 47 /*********************************************************************** 48 49 Initialize the cipher 50 51 Remarks: 52 Returns the cipher state to it's initial value 53 54 ***********************************************************************/ 55 56 override void reset() 57 { 58 super.reset(); 59 context[] = initial[]; 60 } 61 62 /*********************************************************************** 63 64 Obtain the digest 65 66 Returns: 67 the digest 68 69 Remarks: 70 Returns a digest of the current cipher state, this may be the 71 final digest, or a digest of the state between calls to update() 72 73 ***********************************************************************/ 74 75 override void createDigest(ubyte[] buf) 76 { 77 version (BigEndian) 78 ByteSwap.swap32 (context.ptr, context.length * uint.sizeof); 79 80 buf[] = (cast(ubyte[]) context)[]; 81 } 82 83 /*********************************************************************** 84 85 block size 86 87 Returns: 88 the block size 89 90 Remarks: 91 Specifies the size (in bytes) of the block of data to pass to 92 each call to transform(). For MD4 the blockSize is 64. 93 94 ***********************************************************************/ 95 96 protected override uint blockSize() { return 64; } 97 98 /*********************************************************************** 99 100 Length padding size 101 102 Returns: 103 the length padding size 104 105 Remarks: 106 Specifies the size (in bytes) of the padding which uses the 107 length of the data which has been ciphered, this padding is 108 carried out by the padLength method. For MD4 the addSize is 8. 109 110 ***********************************************************************/ 111 112 protected override uint addSize() { return 8; } 113 114 /*********************************************************************** 115 116 Pads the cipher data 117 118 Params: 119 data = a slice of the cipher buffer to fill with padding 120 121 Remarks: 122 Fills the passed buffer slice with the appropriate padding for 123 the final call to transform(). This padding will fill the cipher 124 buffer up to blockSize()-addSize(). 125 126 ***********************************************************************/ 127 128 protected override void padMessage(ubyte[] data) 129 { 130 data[0] = padChar; 131 data[1..$] = 0; 132 } 133 134 /*********************************************************************** 135 136 Performs the length padding 137 138 Params: 139 data = the slice of the cipher buffer to fill with padding 140 length = the length of the data which has been ciphered 141 142 Remarks: 143 Fills the passed buffer slice with addSize() bytes of padding 144 based on the length in bytes of the input data which has been 145 ciphered. 146 147 ***********************************************************************/ 148 149 protected override void padLength(ubyte[] data, ulong length) 150 { 151 length <<= 3; 152 littleEndian64((cast(ubyte*)&length)[0..8],cast(ulong[]) data); 153 } 154 155 /*********************************************************************** 156 157 Performs the cipher on a block of data 158 159 Params: 160 data = the block of data to cipher 161 162 Remarks: 163 The actual cipher algorithm is carried out by this method on 164 the passed block of data. This method is called for every 165 blockSize() bytes of input data and once more with the remaining 166 data padded to blockSize(). 167 168 ***********************************************************************/ 169 170 protected override void transform(const(ubyte[]) input) 171 { 172 uint a,b,c,d; 173 uint[16] x; 174 175 littleEndian32(input,x); 176 177 a = context[0]; 178 b = context[1]; 179 c = context[2]; 180 d = context[3]; 181 182 /* Round 1 */ 183 ff(a, b, c, d, x[ 0], S11, 0); /* 1 */ 184 ff(d, a, b, c, x[ 1], S12, 0); /* 2 */ 185 ff(c, d, a, b, x[ 2], S13, 0); /* 3 */ 186 ff(b, c, d, a, x[ 3], S14, 0); /* 4 */ 187 ff(a, b, c, d, x[ 4], S11, 0); /* 5 */ 188 ff(d, a, b, c, x[ 5], S12, 0); /* 6 */ 189 ff(c, d, a, b, x[ 6], S13, 0); /* 7 */ 190 ff(b, c, d, a, x[ 7], S14, 0); /* 8 */ 191 ff(a, b, c, d, x[ 8], S11, 0); /* 9 */ 192 ff(d, a, b, c, x[ 9], S12, 0); /* 10 */ 193 ff(c, d, a, b, x[10], S13, 0); /* 11 */ 194 ff(b, c, d, a, x[11], S14, 0); /* 12 */ 195 ff(a, b, c, d, x[12], S11, 0); /* 13 */ 196 ff(d, a, b, c, x[13], S12, 0); /* 14 */ 197 ff(c, d, a, b, x[14], S13, 0); /* 15 */ 198 ff(b, c, d, a, x[15], S14, 0); /* 16 */ 199 200 /* Round 2 */ 201 gg(a, b, c, d, x[ 0], S21, 0x5a827999); /* 17 */ 202 gg(d, a, b, c, x[ 4], S22, 0x5a827999); /* 18 */ 203 gg(c, d, a, b, x[ 8], S23, 0x5a827999); /* 19 */ 204 gg(b, c, d, a, x[12], S24, 0x5a827999); /* 20 */ 205 gg(a, b, c, d, x[ 1], S21, 0x5a827999); /* 21 */ 206 gg(d, a, b, c, x[ 5], S22, 0x5a827999); /* 22 */ 207 gg(c, d, a, b, x[ 9], S23, 0x5a827999); /* 23 */ 208 gg(b, c, d, a, x[13], S24, 0x5a827999); /* 24 */ 209 gg(a, b, c, d, x[ 2], S21, 0x5a827999); /* 25 */ 210 gg(d, a, b, c, x[ 6], S22, 0x5a827999); /* 26 */ 211 gg(c, d, a, b, x[10], S23, 0x5a827999); /* 27 */ 212 gg(b, c, d, a, x[14], S24, 0x5a827999); /* 28 */ 213 gg(a, b, c, d, x[ 3], S21, 0x5a827999); /* 29 */ 214 gg(d, a, b, c, x[ 7], S22, 0x5a827999); /* 30 */ 215 gg(c, d, a, b, x[11], S23, 0x5a827999); /* 31 */ 216 gg(b, c, d, a, x[15], S24, 0x5a827999); /* 32 */ 217 218 /* Round 3 */ 219 hh(a, b, c, d, x[ 0], S31, 0x6ed9eba1); /* 33 */ 220 hh(d, a, b, c, x[ 8], S32, 0x6ed9eba1); /* 34 */ 221 hh(c, d, a, b, x[ 4], S33, 0x6ed9eba1); /* 35 */ 222 hh(b, c, d, a, x[12], S34, 0x6ed9eba1); /* 36 */ 223 hh(a, b, c, d, x[ 2], S31, 0x6ed9eba1); /* 37 */ 224 hh(d, a, b, c, x[10], S32, 0x6ed9eba1); /* 38 */ 225 hh(c, d, a, b, x[ 6], S33, 0x6ed9eba1); /* 39 */ 226 hh(b, c, d, a, x[14], S34, 0x6ed9eba1); /* 40 */ 227 hh(a, b, c, d, x[ 1], S31, 0x6ed9eba1); /* 41 */ 228 hh(d, a, b, c, x[ 9], S32, 0x6ed9eba1); /* 42 */ 229 hh(c, d, a, b, x[ 5], S33, 0x6ed9eba1); /* 43 */ 230 hh(b, c, d, a, x[13], S34, 0x6ed9eba1); /* 44 */ 231 hh(a, b, c, d, x[ 3], S31, 0x6ed9eba1); /* 45 */ 232 hh(d, a, b, c, x[11], S32, 0x6ed9eba1); /* 46 */ 233 hh(c, d, a, b, x[ 7], S33, 0x6ed9eba1); /* 47 */ 234 hh(b, c, d, a, x[15], S34, 0x6ed9eba1); /* 48 */ 235 236 context[0] += a; 237 context[1] += b; 238 context[2] += c; 239 context[3] += d; 240 241 x[] = 0; 242 } 243 244 /*********************************************************************** 245 246 ***********************************************************************/ 247 248 protected static uint f(uint x, uint y, uint z) 249 { 250 return (x&y)|(~x&z); 251 } 252 253 /*********************************************************************** 254 255 ***********************************************************************/ 256 257 protected static uint h(uint x, uint y, uint z) 258 { 259 return x^y^z; 260 } 261 262 /*********************************************************************** 263 264 ***********************************************************************/ 265 266 private static uint g(uint x, uint y, uint z) 267 { 268 return (x&y)|(x&z)|(y&z); 269 } 270 271 /*********************************************************************** 272 273 ***********************************************************************/ 274 275 private static void ff(ref uint a, uint b, uint c, uint d, uint x, uint s, uint ac) 276 { 277 a += f(b, c, d) + x + ac; 278 a = rotateLeft(a, s); 279 } 280 281 /*********************************************************************** 282 283 ***********************************************************************/ 284 285 private static void gg(ref uint a, uint b, uint c, uint d, uint x, uint s, uint ac) 286 { 287 a += g(b, c, d) + x + ac; 288 a = rotateLeft(a, s); 289 } 290 291 /*********************************************************************** 292 293 ***********************************************************************/ 294 295 private static void hh(ref uint a, uint b, uint c, uint d, uint x, uint s, uint ac) 296 { 297 a += h(b, c, d) + x + ac; 298 a = rotateLeft(a, s); 299 } 300 301 /*********************************************************************** 302 303 ***********************************************************************/ 304 305 private static const uint[4] initial = 306 [ 307 0x67452301, 308 0xefcdab89, 309 0x98badcfe, 310 0x10325476 311 ]; 312 313 /*********************************************************************** 314 315 ***********************************************************************/ 316 317 private static enum 318 { 319 S11 = 3, 320 S12 = 7, 321 S13 = 11, 322 S14 = 19, 323 S21 = 3, 324 S22 = 5, 325 S23 = 9, 326 S24 = 13, 327 S31 = 3, 328 S32 = 9, 329 S33 = 11, 330 S34 = 15, 331 } 332 } 333 334 335 /******************************************************************************* 336 337 *******************************************************************************/ 338 339 debug(UnitTest) 340 { 341 unittest 342 { 343 __gshared immutable immutable(char)[][] strings = 344 [ 345 "", 346 "a", 347 "abc", 348 "message digest", 349 "abcdefghijklmnopqrstuvwxyz", 350 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 351 "12345678901234567890123456789012345678901234567890123456789012345678901234567890" 352 ]; 353 354 __gshared immutable immutable(char)[][] results = 355 [ 356 "31d6cfe0d16ae931b73c59d7e0c089c0", 357 "bde52cb31de33e46245e05fbdbd6fb24", 358 "a448017aaf21d8525fc10ae87aa6729d", 359 "d9130a8164549fe818874806e1c7014b", 360 "d79e1c308aa5bbcdeea8ed63df412da9", 361 "043f8582f241db351ce627e153e7f0e4", 362 "e33b4ddc9c38f2199c3e7b164fcc0536" 363 ]; 364 365 Md4 h = new Md4(); 366 367 foreach (int i, immutable(char)[] s; strings) 368 { 369 h.update(s); 370 char[] d = h.hexDigest(); 371 assert(d == results[i],":("~s~")("~d~")!=("~results[i]~")"); 372 } 373 } 374 } 375