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 MD5 Message Digest Algorithm as described 12 by RFC 1321 The MD5 Message-Digest Algorithm. R. Rivest. April 1992. 13 14 *******************************************************************************/ 15 16 module tango.util.digest.Md5; 17 18 public import tango.util.digest.Md4; 19 20 private import tango.util.digest.MerkleDamgard; 21 22 /******************************************************************************* 23 24 *******************************************************************************/ 25 26 final class Md5 : Md4 27 { 28 /*********************************************************************** 29 30 ***********************************************************************/ 31 32 private enum 33 { 34 S11 = 7, 35 S12 = 12, 36 S13 = 17, 37 S14 = 22, 38 S21 = 5, 39 S22 = 9, 40 S23 = 14, 41 S24 = 20, 42 S31 = 4, 43 S32 = 11, 44 S33 = 16, 45 S34 = 23, 46 S41 = 6, 47 S42 = 10, 48 S43 = 15, 49 S44 = 21 50 }; 51 52 /*********************************************************************** 53 54 Construct an Md5 55 56 ***********************************************************************/ 57 58 this() { } 59 60 61 /*********************************************************************** 62 63 Performs the cipher on a block of data 64 65 Params: 66 data = the block of data to cipher 67 68 Remarks: 69 The actual cipher algorithm is carried out by this method on 70 the passed block of data. This method is called for every 71 blockSize() bytes of input data and once more with the remaining 72 data padded to blockSize(). 73 74 ***********************************************************************/ 75 76 protected override void transform(const(ubyte[]) input) 77 { 78 uint a,b,c,d; 79 uint[16] x; 80 81 littleEndian32(input,x); 82 83 a = context[0]; 84 b = context[1]; 85 c = context[2]; 86 d = context[3]; 87 88 /* Round 1 */ 89 ff(a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ 90 ff(d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ 91 ff(c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ 92 ff(b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ 93 ff(a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ 94 ff(d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ 95 ff(c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ 96 ff(b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ 97 ff(a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ 98 ff(d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ 99 ff(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ 100 ff(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ 101 ff(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ 102 ff(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ 103 ff(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ 104 ff(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ 105 106 /* Round 2 */ 107 gg(a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ 108 gg(d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ 109 gg(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ 110 gg(b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ 111 gg(a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ 112 gg(d, a, b, c, x[10], S22, 0x2441453); /* 22 */ 113 gg(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ 114 gg(b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ 115 gg(a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ 116 gg(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ 117 gg(c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ 118 gg(b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ 119 gg(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ 120 gg(d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ 121 gg(c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ 122 gg(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ 123 124 /* Round 3 */ 125 hh(a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ 126 hh(d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ 127 hh(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ 128 hh(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ 129 hh(a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ 130 hh(d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ 131 hh(c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ 132 hh(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ 133 hh(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ 134 hh(d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ 135 hh(c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ 136 hh(b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ 137 hh(a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ 138 hh(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ 139 hh(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ 140 hh(b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ 141 142 /* Round 4 */ /* Md5 not md4 */ 143 ii(a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ 144 ii(d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ 145 ii(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ 146 ii(b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ 147 ii(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ 148 ii(d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ 149 ii(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ 150 ii(b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ 151 ii(a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ 152 ii(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ 153 ii(c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ 154 ii(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ 155 ii(a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ 156 ii(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ 157 ii(c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ 158 ii(b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ 159 160 context[0] += a; 161 context[1] += b; 162 context[2] += c; 163 context[3] += d; 164 165 x[] = 0; 166 } 167 168 /*********************************************************************** 169 170 ***********************************************************************/ 171 172 private static uint g(uint x, uint y, uint z) 173 { 174 return (x&z)|(y&~z); 175 } 176 177 /*********************************************************************** 178 179 ***********************************************************************/ 180 181 private static uint i(uint x, uint y, uint z) 182 { 183 return y^(x|~z); 184 } 185 186 /*********************************************************************** 187 188 ***********************************************************************/ 189 190 private static void ff(ref uint a, uint b, uint c, uint d, uint x, uint s, uint ac) 191 { 192 a += f(b, c, d) + x + ac; 193 a = rotateLeft(a, s); 194 a += b; 195 } 196 197 /*********************************************************************** 198 199 ***********************************************************************/ 200 201 private static void gg(ref uint a, uint b, uint c, uint d, uint x, uint s, uint ac) 202 { 203 a += g(b, c, d) + x + ac; 204 a = rotateLeft(a, s); 205 a += b; 206 } 207 208 /*********************************************************************** 209 210 ***********************************************************************/ 211 212 private static void hh(ref uint a, uint b, uint c, uint d, uint x, uint s, uint ac) 213 { 214 a += h(b, c, d) + x + ac; 215 a = rotateLeft(a, s); 216 a += b; 217 } 218 219 /*********************************************************************** 220 221 ***********************************************************************/ 222 223 private static void ii(ref uint a, uint b, uint c, uint d, uint x, uint s, uint ac) 224 { 225 a += i(b, c, d) + x + ac; 226 a = rotateLeft(a, s); 227 a += b; 228 } 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 "d41d8cd98f00b204e9800998ecf8427e", 254 "0cc175b9c0f1b6a831c399e269772661", 255 "900150983cd24fb0d6963f7d28e17f72", 256 "f96b697d7cb7938d525a2f31aaf161d0", 257 "c3fcd3d76192e4007dfb496cca67e13b", 258 "d174ab98d277d9f5a5611c2c9f419d9f", 259 "57edf4a22be3c955ac49da2e2107b67a" 260 ]; 261 262 Md5 h = new Md5(); 263 264 foreach (int i, immutable(char)[] s; strings) 265 { 266 h.update(cast(ubyte[]) s); 267 char[] d = h.hexDigest(); 268 269 assert(d == results[i],":("~s~")("~d~")!=("~results[i]~")"); 270 } 271 } 272 }