/* md5.d - RSA Data Security, Inc., MD5 message-digest algorithm * Derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm. */ /* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All rights reserved. License to copy and use this software is granted provided that it is identified as the "RSA Data Security, Inc. MD5 Message-Digest Algorithm" in all material mentioning or referencing this software or this function. License is also granted to make and use derivative works provided that such works are identified as "derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm" in all material mentioning or referencing the derived work. RSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of this software for any particular purpose. It is provided "as is" without express or implied warranty of any kind. These notices must be retained in any copies of any part of this documentation and/or software. */ module regans.md5; static uint state[4] = [ 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 ]; static char[64] padding = [ 0x80 ]; static uint S11 = 7; static uint S12 = 12; static uint S13 = 17; static uint S14 = 22; static uint S21 = 5; static uint S22 = 9; static uint S23 = 14; static uint S24 = 20; static uint S31 = 4; static uint S32 = 11; static uint S33 = 16; static uint S34 = 23; static uint S41 = 6; static uint S42 = 10; static uint S43 = 15; static uint S44 = 21; class MD5 { unittest { auto MD5 m = new MD5(); m.reset(); m.process(""); assert(m.toString() == "d41d8cd98f00b204e9800998ecf8427e"); m.reset(); m.process("a"); assert(m.toString() == "0cc175b9c0f1b6a831c399e269772661"); m.reset(); m.process("abc"); assert(m.toString() == "900150983cd24fb0d6963f7d28e17f72"); m.reset(); m.process("message digest"); assert(m.toString() == "f96b697d7cb7938d525a2f31aaf161d0"); m.reset(); m.process("abcdefghijklmnopqrstuvwxyz"); assert(m.toString() == "c3fcd3d76192e4007dfb496cca67e13b"); m.reset(); m.process("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); assert(m.toString() == "d174ab98d277d9f5a5611c2c9f419d9f"); m.reset(); m.process("12345678901234567890123456789012345678901234567890123456789012345678901234567890"); assert(m.toString() == "57edf4a22be3c955ac49da2e2107b67a"); } this() { reset(); } void reset() { state[] = .state; count[] = 0; md5.length = 0; buffer.length = 0; } void process(char[] input) { uint i; addBits(input.length); buffer ~= input[]; for(i = 0; i+63 < buffer.length; i += 64) { transform(buffer[i..i+64]); } buffer = buffer[i..buffer.length]; } char[] get() { if (md5.length == 0) { char[] bits; uint i,b; bits = encode(count); b = getBytes(); i = (b < 56) ? (56 - b) : (120 - b); process(padding[0..i]); process(bits); md5 = encode(state); } return md5; } char[] toString() { char[] result; int i; result.length = 32; get(); for(i = 0; i < 16; i ++) { result[i*2] = "0123456789abcdef"[md5[i]/16]; result[i*2+1] = "0123456789abcdef"[md5[i]%16]; } return result; } private: char[] buffer; char[] md5; uint state[4]; uint count[2]; void addBits(uint bytes) { count[0] += bytes << 3; if (count[0] < bytes << 3) count[1]++; count[1] += bytes >> 29; } uint getBytes() { return (count[0] >> 3) & 0x3f; } void transform(char[] block) { uint a,b,c,d; uint[] x; x = decode(block); a = state[0]; b = state[1]; c = state[2]; d = state[3]; /* Round 1 */ ff(a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ ff(d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ ff(c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ ff(b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ ff(a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ ff(d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ ff(c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ ff(b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ ff(a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ ff(d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ ff(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ ff(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ ff(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ ff(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ ff(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ ff(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ /* Round 2 */ gg(a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ gg(d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ gg(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ gg(b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ gg(a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ gg(d, a, b, c, x[10], S22, 0x2441453); /* 22 */ gg(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ gg(b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ gg(a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ gg(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ gg (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ gg(b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ gg(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ gg(d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ gg(c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ gg(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ /* Round 3 */ hh(a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ hh(d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ hh(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ hh(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ hh(a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ hh(d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ hh(c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ hh(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ hh(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ hh(d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ hh(c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ hh(b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ hh(a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ hh(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ hh(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ hh(b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ /* Round 4 */ ii(a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ ii(d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ ii(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ ii(b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ ii(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ ii(d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ ii(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ ii(b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ ii(a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ ii(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ ii(c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ ii(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ ii(a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ ii(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ ii(c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ ii(b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; x[] = 0; } } char[] encode(uint[] value) in { } out (result) { //assert(decode(result) == value); } body{ char[] result; uint i; result.length = value.length*4; for(i = 0; i < result.length; i += 4) { result[i] = value[i/4] & 0xff; result[i+1] = (value[i/4] >> 8) & 0xff; result[i+2] = (value[i/4] >> 16) & 0xff; result[i+3] = (value[i/4] >> 24) & 0xff; } return result; } uint[] decode(char[] block) in { } out (result) { //assert(encode(result) == block); } body { uint[] result; uint i; result.length = block.length/4; for (i = 0; i < block.length; i += 4) { result[i/4] = block[i] | (block[i+1] << 8) | (block[i+2] << 16) | (block[i+3] << 24); } return result; } uint f(uint x, uint y, uint z) { return (x & y) | (~x & z); } uint g(uint x, uint y, uint z) { return (x & z) | (y & ~z); } uint h(uint x, uint y, uint z) { return x ^ y ^ z; } uint i(uint x, uint y, uint z) { return y ^ (x | ~z); } uint rotateLeft(uint x, uint n) { return (x << n) | (x >> (32-n)); } void ff(inout uint a, uint b, uint c, uint d, uint x, uint s, uint ac) { a += f(b, c, d) + x + ac; a = rotateLeft(a, s); a += b; } void gg(inout uint a, uint b, uint c, uint d, uint x, uint s, uint ac) { a += g(b, c, d) + x + ac; a = rotateLeft(a, s); a += b; } void hh(inout uint a, uint b, uint c, uint d, uint x, uint s, uint ac) { a += h(b, c, d) + x + ac; a = rotateLeft(a, s); a += b; } void ii(inout uint a, uint b, uint c, uint d, uint x, uint s, uint ac) { a += i(b, c, d) + x + ac; a = rotateLeft(a, s); a += b; }