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