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]~")");
+            }
+        }
+    }
+}