MD4

From Rosetta Code
Revision as of 19:42, 26 March 2012 by rosettacode>Kernigh (MD4 is an obsolete hash function. Start with Ruby.)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
MD4 is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

MD4 is an obsolete hash function; it computes a 128-bit message digest. In 1992, its authors designed MD4 as a secure hash function, but by 1996, MD4 had collisions. MD4 provides no security, and appears only in obsolete protocols. In short, MD4 is useless.

Parts of MD4's design survive in later algorithms, including MD5, SHA-1 and RIPEMD-160. (Today, MD5 is also obsolete.) Like those later algorithms, MD4 pads the message to a multiple of 64 octets. MD4's padding is identical with RIPEMD-160 and almost identical with SHA-1. (MD4 uses little endian, SHA-1 uses big endian.) Like those later algorithms, MD4 interprets each block as an array of 16 words, where each word is 32 bits.

RFC 1320 specifies the MD4 algorithm. RFC 6150 declares that MD4 is obsolete.

Find the MD4 message digest of a string of octets. You may either call an MD4 library, or implement MD4 in your language.

Ruby

These programs print the MD4 digest of 'Rosetta Code', which is a52bcfc6a0d0d300cdc5ddbfbefe478b.

Use 'openssl' from Ruby's standard library.

Library: OpenSSL

<lang ruby>require 'openssl' puts OpenSSL::Digest::MD4.hexdigest('Rosetta Code')</lang>

Implement MD4 in Ruby.

<lang ruby>require 'stringio'

  1. Calculates MD4 message digest of _string_. Returns digest as
  2. binary string.

def md4(string)

 # functions
 mask = (1 << 32) - 1
 f = proc {|x, y, z| x & y | x.^(mask) & z}
 g = proc {|x, y, z| x & y | x & z | y & z}
 h = proc {|x, y, z| x ^ y ^ z}
 r = proc {|v, s| (v << s).&(mask) | (v.&(mask) >> (32 - s))}
 # initial hash
 a, b, c, d = 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476
 io = StringIO.new(string)
 block = ""
 term = false  # appended "\x80" in second-last block?
 last = false  # last block?
 until last
   # Read next block of 16 words (64 bytes, 512 bits).
   io.read(64, block) or (
     # Work around a bug in Rubinius 1.2.4. At eof,
     # MRI and JRuby already replace block with "".
     block.replace("")
   )
   # Unpack block into 32-bit words "V".
   case len = block.length
   when 64
     # Unpack 16 words.
     x = block.unpack("V16")
   when 56..63
     # Second-last block: append padding, unpack 16 words.
     block.concat("\x80"); term = true
     block.concat("\0" * (63 - len))
     x = block.unpack("V16")
   when 0..55
     # Last block: append padding, unpack 14 words.
     block.concat(term ? "\0" : "\x80")
     block.concat("\0" * (55 - len))
     x = block.unpack("V14")
     # Append bit length, 2 words.
     bit_len = string.length << 3
     x.push(bit_len & mask, bit_len >> 32)
     last = true
   else
     fail "impossible"
   end
   # Process this block.
   aa, bb, cc, dd = a, b, c, d
   [0, 4, 8, 12].each {|i|
     a = r[a + f[b, c, d] + x[i],  3]; i += 1
     d = r[d + f[a, b, c] + x[i],  7]; i += 1
     c = r[c + f[d, a, b] + x[i], 11]; i += 1
     b = r[b + f[c, d, a] + x[i], 19]
   }
   [0, 1, 2, 3].each {|i|
     a = r[a + g[b, c, d] + x[i] + 0x5a827999,  3]; i += 4
     d = r[d + g[a, b, c] + x[i] + 0x5a827999,  5]; i += 4
     c = r[c + g[d, a, b] + x[i] + 0x5a827999,  9]; i += 4
     b = r[b + g[c, d, a] + x[i] + 0x5a827999, 13]
   }
   [0, 2, 1, 3].each {|i|
     a = r[a + h[b, c, d] + x[i] + 0x6ed9eba1,  3]; i += 8
     d = r[d + h[a, b, c] + x[i] + 0x6ed9eba1,  9]; i -= 4
     c = r[c + h[d, a, b] + x[i] + 0x6ed9eba1, 11]; i += 8
     b = r[b + h[c, d, a] + x[i] + 0x6ed9eba1, 15]
   }
   a = (a + aa) & mask
   b = (b + bb) & mask
   c = (c + cc) & mask
   d = (d + dd) & mask
 end
 [a, b, c, d].pack("V4")

end

  1. Hexadecimal-encode a binary _string_.

def hexencode(string)

 # We use String#each_byte for compatibility with Ruby 1.8.6.
 result = ""
 string.each_byte {|byte| result << ("%02x" % byte)}
 result

end

if __FILE__ == $0

 # Print an example MD4 digest.
 str = 'Rosetta Code'
 printf "%s:\n  %s\n", str, hexencode(md4(str))

end</lang>