Mercurial > projects > dcrypt
view dcrypt/crypto/hashes/MD4.d @ 28:ad687db713a4
Further reworked the code for hash padding. Replaced all instances of 'char[]' with 'string' and removed a few 'const' modifiers as per Glenn Haecker's patch for D2 compatibility. Updated CONTRIBUTORS file.
author | Thomas Dixon <reikon@reikon.us> |
---|---|
date | Sun, 10 May 2009 22:38:48 -0400 |
parents | 8b5eaf3c2979 |
children |
line wrap: on
line source
/** * This file is part of the dcrypt project. * * Copyright: Copyright (C) dcrypt contributors 2009. All rights reserved. * License: MIT * Authors: Thomas Dixon */ module dcrypt.crypto.hashes.MD4; public import dcrypt.crypto.Hash; /** * Implementation of Ron Rivest's MD4. * * Conforms: RFC 1320 * References: http://www.faqs.org/rfcs/rfc1320.html * Bugs: MD4 is not cryptographically secure. */ class MD4 : Hash { private uint h0, h1, h2, h3; // Shift amounts private enum { S11 = 3, S12 = 7, S13 = 11, S14 = 19, S21 = 3, S22 = 5, S23 = 9, S24 = 13, S31 = 3, S32 = 9, S33 = 11, S34 = 15 }; this (void[] input_=null) { reset(); super(input_); } uint blockSize() { return 64; } uint digestSize() { return 16; } string name() { return "MD4"; } void transform(ubyte[] input) { uint[] w = new uint[16]; for (int i = 0, j = 0; i < 16; i++,j+=int.sizeof) w[i] = ByteConverter.LittleEndian.to!(uint)(input[j..j+int.sizeof]); uint a = h0, b = h1, c = h2, d = h3; // Round 1 ff(a, b, c, d, w[ 0], S11); ff(d, a, b, c, w[ 1], S12); ff(c, d, a, b, w[ 2], S13); ff(b, c, d, a, w[ 3], S14); ff(a, b, c, d, w[ 4], S11); ff(d, a, b, c, w[ 5], S12); ff(c, d, a, b, w[ 6], S13); ff(b, c, d, a, w[ 7], S14); ff(a, b, c, d, w[ 8], S11); ff(d, a, b, c, w[ 9], S12); ff(c, d, a, b, w[10], S13); ff(b, c, d, a, w[11], S14); ff(a, b, c, d, w[12], S11); ff(d, a, b, c, w[13], S12); ff(c, d, a, b, w[14], S13); ff(b, c, d, a, w[15], S14); // Round 2 gg(a, b, c, d, w[ 0], S21); gg(d, a, b, c, w[ 4], S22); gg(c, d, a, b, w[ 8], S23); gg(b, c, d, a, w[12], S24); gg(a, b, c, d, w[ 1], S21); gg(d, a, b, c, w[ 5], S22); gg(c, d, a, b, w[ 9], S23); gg(b, c, d, a, w[13], S24); gg(a, b, c, d, w[ 2], S21); gg(d, a, b, c, w[ 6], S22); gg(c, d, a, b, w[10], S23); gg(b, c, d, a, w[14], S24); gg(a, b, c, d, w[ 3], S21); gg(d, a, b, c, w[ 7], S22); gg(c, d, a, b, w[11], S23); gg(b, c, d, a, w[15], S24); // Round 3 hh(a, b, c, d, w[ 0], S31); hh(d, a, b, c, w[ 8], S32); hh(c, d, a, b, w[ 4], S33); hh(b, c, d, a, w[12], S34); hh(a, b, c, d, w[ 2], S31); hh(d, a, b, c, w[10], S32); hh(c, d, a, b, w[ 6], S33); hh(b, c, d, a, w[14], S34); hh(a, b, c, d, w[ 1], S31); hh(d, a, b, c, w[ 9], S32); hh(c, d, a, b, w[ 5], S33); hh(b, c, d, a, w[13], S34); hh(a, b, c, d, w[ 3], S31); hh(d, a, b, c, w[11], S32); hh(c, d, a, b, w[ 7], S33); hh(b, c, d, a, w[15], S34); h0 += a; h1 += b; h2 += c; h3 += d; } 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&y)|(x&z)|(y&z); } private void ff(ref uint a, uint b, uint c, uint d, uint x, uint s) { a += f(b, c, d) + x; a = Bitwise.rotateLeft(a, s); } private void gg(ref uint a, uint b, uint c, uint d, uint x, uint s) { a += g(b, c, d) + x + 0x5a827999u; a = Bitwise.rotateLeft(a, s); } private void hh(ref uint a, uint b, uint c, uint d, uint x, uint s) { a += h(b, c, d) + x + 0x6ed9eba1u; a = Bitwise.rotateLeft(a, s); } ubyte[] digest() { padMessage(MODE_MD); ubyte[] result = new ubyte[digestSize]; result[0..4] = ByteConverter.LittleEndian.from!(uint)(h0); result[4..8] = ByteConverter.LittleEndian.from!(uint)(h1); result[8..12] = ByteConverter.LittleEndian.from!(uint)(h2); result[12..16] = ByteConverter.LittleEndian.from!(uint)(h3); reset(); return result; } void reset() { super.reset(); h0 = 0x67452301u; h1 = 0xefcdab89u; h2 = 0x98badcfeu; h3 = 0x10325476u; } MD4 copy() { MD4 h = new MD4(buffer[0..index]); h.bytes = bytes; h.h0 = h0; h.h1 = h1; h.h2 = h2; h.h3 = h3; return h; } debug (UnitTest) { unittest { static string[] test_inputs = [ "", "a", "abc", "message digest", "abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "12345678901234567890123456789012345678901234567890123456789012345678901234567890" ]; static string[] test_results = [ "31d6cfe0d16ae931b73c59d7e0c089c0", "bde52cb31de33e46245e05fbdbd6fb24", "a448017aaf21d8525fc10ae87aa6729d", "d9130a8164549fe818874806e1c7014b", "d79e1c308aa5bbcdeea8ed63df412da9", "043f8582f241db351ce627e153e7f0e4", "e33b4ddc9c38f2199c3e7b164fcc0536" ]; MD4 h = new MD4(); foreach (uint i, string input; test_inputs) { h.update(input); string digest = h.hexDigest(); assert(digest == test_results[i], h.name~": ("~digest~") != ("~test_results[i]~")"); } } } }