Mercurial > projects > dcrypt
diff dcrypt/crypto/hashes/MD5.d @ 0:0e08791a1418
Initial import.
author | Thomas Dixon <reikon@reikon.us> |
---|---|
date | Sun, 10 Aug 2008 14:20:17 -0400 |
parents | |
children | 71aae178f89a |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dcrypt/crypto/hashes/MD5.d Sun Aug 10 14:20:17 2008 -0400 @@ -0,0 +1,245 @@ +/** + * This file is part of the dcrypt project. + * + * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved. + * License: MIT + * Authors: Thomas Dixon + */ + +module dcrypt.crypto.hashes.MD5; + +public import dcrypt.crypto.Hash; + +/** Implementation of Ron Rivest's MD5. */ +class MD5 : Hash { + private uint h0, h1, h2, h3; + + // Shift amounts + private enum { + S11 = 7, + S12 = 12, + S13 = 17, + S14 = 22, + + S21 = 5, + S22 = 9, + S23 = 14, + S24 = 20, + + S31 = 4, + S32 = 11, + S33 = 16, + S34 = 23, + + S41 = 6, + S42 = 10, + S43 = 15, + S44 = 21 + }; + + this (void[] input_=null) { + reset(); + super(input_); + } + + uint blockSize() { + return 64; + } + + uint digestSize() { + return 16; + } + + char[] name() { + return "MD5"; + } + + void transform(ubyte[] input) { + uint[] w = new uint[16]; + + for (int i = 0, j = 0; i < 16; i++,j+=4) + w[i] = Util.ubytesToUintLittle(input, j); + + uint a = h0, + b = h1, + c = h2, + d = h3; + + // Round 1 -- FIGHT! + ff(a, b, c, d, w[ 0], S11, 3614090360); /* 1 */ + ff(d, a, b, c, w[ 1], S12, 3905402710); /* 2 */ + ff(c, d, a, b, w[ 2], S13, 606105819); /* 3 */ + ff(b, c, d, a, w[ 3], S14, 3250441966); /* 4 */ + ff(a, b, c, d, w[ 4], S11, 4118548399); /* 5 */ + ff(d, a, b, c, w[ 5], S12, 1200080426); /* 6 */ + ff(c, d, a, b, w[ 6], S13, 2821735955); /* 7 */ + ff(b, c, d, a, w[ 7], S14, 4249261313); /* 8 */ + ff(a, b, c, d, w[ 8], S11, 1770035416); /* 9 */ + ff(d, a, b, c, w[ 9], S12, 2336552879); /* 10 */ + ff(c, d, a, b, w[10], S13, 4294925233); /* 11 */ + ff(b, c, d, a, w[11], S14, 2304563134); /* 12 */ + ff(a, b, c, d, w[12], S11, 1804603682); /* 13 */ + ff(d, a, b, c, w[13], S12, 4254626195); /* 14 */ + ff(c, d, a, b, w[14], S13, 2792965006); /* 15 */ + ff(b, c, d, a, w[15], S14, 1236535329); /* 16 */ + + // Round 2 + gg(a, b, c, d, w[ 1], S21, 4129170786); /* 17 */ + gg(d, a, b, c, w[ 6], S22, 3225465664); /* 18 */ + gg(c, d, a, b, w[11], S23, 643717713); /* 19 */ + gg(b, c, d, a, w[ 0], S24, 3921069994); /* 20 */ + gg(a, b, c, d, w[ 5], S21, 3593408605); /* 21 */ + gg(d, a, b, c, w[10], S22, 38016083); /* 22 */ + gg(c, d, a, b, w[15], S23, 3634488961); /* 23 */ + gg(b, c, d, a, w[ 4], S24, 3889429448); /* 24 */ + gg(a, b, c, d, w[ 9], S21, 568446438); /* 25 */ + gg(d, a, b, c, w[14], S22, 3275163606); /* 26 */ + gg(c, d, a, b, w[ 3], S23, 4107603335); /* 27 */ + gg(b, c, d, a, w[ 8], S24, 1163531501); /* 28 */ + gg(a, b, c, d, w[13], S21, 2850285829); /* 29 */ + gg(d, a, b, c, w[ 2], S22, 4243563512); /* 30 */ + gg(c, d, a, b, w[ 7], S23, 1735328473); /* 31 */ + gg(b, c, d, a, w[12], S24, 2368359562); /* 32 */ + + // Round 3 + hh(a, b, c, d, w[ 5], S31, 4294588738); /* 33 */ + hh(d, a, b, c, w[ 8], S32, 2272392833); /* 34 */ + hh(c, d, a, b, w[11], S33, 1839030562); /* 35 */ + hh(b, c, d, a, w[14], S34, 4259657740); /* 36 */ + hh(a, b, c, d, w[ 1], S31, 2763975236); /* 37 */ + hh(d, a, b, c, w[ 4], S32, 1272893353); /* 38 */ + hh(c, d, a, b, w[ 7], S33, 4139469664); /* 39 */ + hh(b, c, d, a, w[10], S34, 3200236656); /* 40 */ + hh(a, b, c, d, w[13], S31, 681279174); /* 41 */ + hh(d, a, b, c, w[ 0], S32, 3936430074); /* 42 */ + hh(c, d, a, b, w[ 3], S33, 3572445317); /* 43 */ + hh(b, c, d, a, w[ 6], S34, 76029189); /* 44 */ + hh(a, b, c, d, w[ 9], S31, 3654602809); /* 45 */ + hh(d, a, b, c, w[12], S32, 3873151461); /* 46 */ + hh(c, d, a, b, w[15], S33, 530742520); /* 47 */ + hh(b, c, d, a, w[ 2], S34, 3299628645); /* 48 */ + + // Round 4 + ii(a, b, c, d, w[ 0], S41, 4096336452); /* 49 */ + ii(d, a, b, c, w[ 7], S42, 1126891415); /* 50 */ + ii(c, d, a, b, w[14], S43, 2878612391); /* 51 */ + ii(b, c, d, a, w[ 5], S44, 4237533241); /* 52 */ + ii(a, b, c, d, w[12], S41, 1700485571); /* 53 */ + ii(d, a, b, c, w[ 3], S42, 2399980690); /* 54 */ + ii(c, d, a, b, w[10], S43, 4293915773); /* 55 */ + ii(b, c, d, a, w[ 1], S44, 2240044497); /* 56 */ + ii(a, b, c, d, w[ 8], S41, 1873313359); /* 57 */ + ii(d, a, b, c, w[15], S42, 4264355552); /* 58 */ + ii(c, d, a, b, w[ 6], S43, 2734768916); /* 59 */ + ii(b, c, d, a, w[13], S44, 1309151649); /* 60 */ + ii(a, b, c, d, w[ 4], S41, 4149444226); /* 61 */ + ii(d, a, b, c, w[11], S42, 3174756917); /* 62 */ + ii(c, d, a, b, w[ 2], S43, 718787259); /* 63 */ + ii(b, c, d, a, w[ 9], S44, 3951481745); /* 64 */ + + // FINISH HIM! + h0 += a; + h1 += b; + h2 += c; + h3 += d; + // FATALITY! MD5 Wins. \o/ ('cept not because it's insecure, but whatev) + } + + private uint f(uint x, uint y, uint z) { + return (x&y)|(~x&z); + } + + private uint h(uint x, uint y, uint z) { + return x^y^z; + } + + private uint g(uint x, uint y, uint z) { + return (x&z)|(y&~z); + } + + private uint i(uint x, uint y, uint z) { + return y^(x|~z); + } + + private void ff(ref uint a, uint b, uint c, + uint d, uint x, uint s, uint ac) { + a += f(b, c, d) + x + ac; + a = Util.rotateLeft(a, s); + a += b; + } + + private void gg(ref uint a, uint b, uint c, + uint d, uint x, uint s, uint ac) { + a += g(b, c, d) + x + ac; + a = Util.rotateLeft(a, s); + a += b; + } + + private void hh(ref uint a, uint b, uint c, + uint d, uint x, uint s, uint ac) { + a += h(b, c, d) + x + ac; + a = Util.rotateLeft(a, s); + a += b; + } + + private void ii(ref uint a, uint b, uint c, + uint d, uint x, uint s, uint ac) { + a += i(b, c, d) + x + ac; + a = Util.rotateLeft(a, s); + a += b; + } + + ubyte[] digest() { + padMessage(MODE_MD); + ubyte[] result = new ubyte[digestSize]; + + Util.uintToUbytesLittle(h0, result, 0); + Util.uintToUbytesLittle(h1, result, 4); + Util.uintToUbytesLittle(h2, result, 8); + Util.uintToUbytesLittle(h3, result, 12); + + reset(); + return result; + } + + void reset() { + super.reset(); + h0 = 0x67452301u, + h1 = 0xefcdab89u, + h2 = 0x98badcfeu, + h3 = 0x10325476u; + } + + version (UnitTest) { + // Found in Tango <3 + unittest { + static const char[][] test_inputs = [ + "", + "a", + "abc", + "message digest", + "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" + ]; + + static const char[][] test_results = [ + "d41d8cd98f00b204e9800998ecf8427e", + "0cc175b9c0f1b6a831c399e269772661", + "900150983cd24fb0d6963f7d28e17f72", + "f96b697d7cb7938d525a2f31aaf161d0", + "c3fcd3d76192e4007dfb496cca67e13b", + "d174ab98d277d9f5a5611c2c9f419d9f", + "57edf4a22be3c955ac49da2e2107b67a" + ]; + + MD5 h = new MD5(); + foreach (uint i, char[] input; test_inputs) { + h.update(input); + char[] digest = h.hexDigest(); + assert(digest == test_results[i], + h.name()~": ("~digest~") != ("~test_results[i]~")"); + } + } + } +}