gov.sandia.cognition.hash.MD5Hash Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of cognitive-foundry Show documentation
Show all versions of cognitive-foundry Show documentation
A single jar with all the Cognitive Foundry components.
/*
* File: MD5Hash.java
* Authors: Kevin R. Dixon
* Company: Sandia National Laboratories
* Project: Cognitive Foundry
*
* Copyright Jan 26, 2011, Sandia Corporation.
* Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
* license for use of this work by or on behalf of the U.S. Government.
* Export of this program may require a license from the United States
* Government. See CopyrightHistory.txt for complete details.
*
*/
package gov.sandia.cognition.hash;
import gov.sandia.cognition.annotation.PublicationReference;
import gov.sandia.cognition.annotation.PublicationReferences;
import gov.sandia.cognition.annotation.PublicationType;
import gov.sandia.cognition.util.ObjectUtil;
import java.util.Arrays;
// This class computes MD5 hashes.
// Manually translated by Jon Howell
// from some public domain C code (md5.c) included with the ssh-1.2.22 source.
// Tue Jan 19 15:55:50 EST 1999
// $Id: MD5Hash.java,v 1.3 2011/06/28 17:07:08 krdixon Exp $
//
// To compute the message digest of a chunk of bytes, create an
// MD5 object 'md5', call md5.update() as needed on buffers full
// of bytes, and then call md5.md5final(), which
// will fill a supplied 16-byte array with the digest.
//
// A main() method is included that hashes the data on System.in.
//
// It seems to run around 25-30 times slower (JDK1.1.6) than optimized C
// (gcc -O4, version 2.7.2.3). Measured on a Sun Ultra 5 (SPARC 270MHz).
//
// Comments from md5.c from ssh-1.2.22, the basis for this code:
//
/* This code has been heavily hacked by Tatu Ylonen to
make it compile on machines like Cray that don't have a 32 bit integer
type. */
/*
* This code implements the MD5 message-digest algorithm.
* The algorithm is due to Ron Rivest. This code was
* written by Colin Plumb in 1993, no copyright is claimed.
* This code is in the public domain; do with it what you wish.
*
* Equivalent code is available from RSA Data Security, Inc.
* This code has been tested against that, and is equivalent,
* except that you don't need to include two pages of legalese
* with every copy.
*
* To compute the message digest of a chunk of bytes, declare an
* MD5Context structure, pass it to MD5Init, call MD5Update as
* needed on buffers full of bytes, and then call MD5Final, which
* will fill a supplied 16-byte array with the digest.
*/
/**
* Implementation of the MD5 128-bit (16-byte) cryptographic hash function.
* This algorithm is known to be unsafe for cryptographic purposes and
* is implemented for historic purposes only. This implementation is based
* on the Java port of C code by Jon Howell. According to Howell, it is
* 25-30 times slower than the optimized C version. Do not use MD5.
*
* @author Kevin R. Dixon
* @since 3.4.2
*/
@PublicationReferences(
references={
@PublicationReference(
author="Wikipedia",
title="MD5",
type=PublicationType.WebPage,
year=2010
)
,
@PublicationReference(
author="Jon Howell",
title="MD5 Java class",
type=PublicationType.Misc,
year=1999,
url="http://www.jonh.net/~jonh/md5/MD5.java",
notes="A fairly inefficient implementation, but a correct one!"
)
}
)
public class MD5Hash
extends AbstractHashFunction
{
/**
* MD5 is a 128-bit (16-byte) length hash.
*/
public static final int LENGTH = 16;
/**
* Default seed
*/
protected static final byte[] DEFAULT_SEED = {
(byte)0x67, (byte)0x45, (byte)0x23, (byte)0x01,
(byte)0xef, (byte)0xcd, (byte)0xab, (byte)0x89,
(byte)0x98, (byte)0xba, (byte)0xdc, (byte)0xfe,
(byte)0x10, (byte)0x32, (byte)0x54, (byte)0x76
};
/**
* These were originally unsigned ints.
* This Java code makes an effort to avoid sign traps.
* buf[] is where the hash accumulates.
*/
private int buf[];
/**
* This is the count of bits hashed so far.
*/
private long bits;
/**
* This is a buffer where we stash bytes until we have
* enough (64) to perform a transform operation.
*/
private byte in[];
/**
* Default constructor
*/
public MD5Hash()
{
this.buf = new int[4];
this.in = new byte[64];
}
@Override
public void evaluateInto(
byte[] input,
byte[] output,
byte[] seed)
{
if( output.length != LENGTH )
{
throw new IllegalArgumentException(
"Output must be of length " + LENGTH );
}
if( seed.length != LENGTH )
{
throw new IllegalArgumentException(
"Expected seed to be of length: " + LENGTH );
}
if( input == null )
{
Arrays.fill( output, (byte) 0 );
return;
}
// no bits yet.
this.bits = 0L;
// fill the hash accumulator with a seed value
this.buf[0] = HashFunctionUtil.toInteger(seed, 0*4);
this.buf[1] = HashFunctionUtil.toInteger(seed, 1*4);
this.buf[2] = HashFunctionUtil.toInteger(seed, 2*4);
this.buf[3] = HashFunctionUtil.toInteger(seed, 3*4);
this.update(input);
this.md5final(output);
}
@Override
public int length()
{
return LENGTH;
}
@Override
public byte[] getDefaultSeed()
{
return ObjectUtil.deepCopy(DEFAULT_SEED);
}
/**
* Main MD5 update step
* @param newbuf
* new buffer to update
*/
private void update(
byte[] newbuf)
{
update(newbuf, 0, newbuf.length);
}
/**
* Interior MD5 update step
* @param newbuf
* new buffer to update
* @param bufstart
* Offset into the buffer to update
* @param buflen
* how many bytes to update (not necessarily all of them!)
*/
public void update(
byte[] newbuf,
int bufstart,
int buflen)
{
int t;
int len = buflen;
// shash old bits value for the "Bytes already in" computation
// just below.
t = (int) bits; // (int) cast should just drop high bits, I hope
/* update bitcount */
/* the C code used two 32-bit ints separately, and carefully
* ensured that the carry carried.
* Java has a 64-bit long, which is just what the code really wants.
*/
bits += (long) (len << 3);
t = (t >>> 3) & 0x3f; /* Bytes already in this->in */
/* Handle any leading odd-sized chunks */
/* (that is, any left-over chunk left by last update() */
if (t != 0)
{
int p = t;
t = 64 - t;
if (len < t)
{
System.arraycopy(newbuf, bufstart, in, p, len);
return;
}
System.arraycopy(newbuf, bufstart, in, p, t);
transform();
bufstart += t;
len -= t;
}
/* Process data in 64-byte chunks */
while (len >= 64)
{
System.arraycopy(newbuf, bufstart, in, 0, 64);
this.transform();
bufstart += 64;
len -= 64;
}
/* Handle any remaining bytes of data. */
/* that is, stash them for the next update(). */
System.arraycopy(newbuf, bufstart, in, 0, len);
}
/**
* Final wrapup - pad to 64-byte boundary with the bit pattern
* 1 0* (64-bit count of bits processed, MSB-first)
* @param digest
* Output value from the hash code
*/
private void md5final(
byte[] digest)
{
/* "final" is a poor method name in Java. :v) */
int count;
int p; // in original code, this is a pointer; in this java code
// it's an index into the array this->in.
/* Compute number of bytes mod 64 */
count = (int) ((bits >>> 3) & 0x3F);
/* Set the first char of padding to 0x80. This is safe since there is
always at least one byte free */
p = count;
in[p++] = (byte) 0x80;
/* Bytes of padding needed to make 64 bytes */
count = 64 - 1 - count;
/* Pad out to 56 mod 64 */
if (count < 8)
{
/* Two lots of padding: Pad the first block to 64 bytes */
zeroByteArray(in, p, count);
transform();
/* Now fill the next block with 56 bytes */
zeroByteArray(in, 0, 56);
}
else
{
/* Pad block to 56 bytes */
zeroByteArray(in, p, count - 8);
}
/* Append length in bits and transform */
// Could use a PUT_64BIT... func here. This is a fairly
// direct translation from the C code, where bits was an array
// of two 32-bit ints.
int lowbits = (int) bits;
int highbits = (int) (bits >>> 32);
PUT_32BIT_LSB_FIRST(in, 56, lowbits);
PUT_32BIT_LSB_FIRST(in, 60, highbits);
transform();
PUT_32BIT_LSB_FIRST(digest, 0, buf[0]);
PUT_32BIT_LSB_FIRST(digest, 4, buf[1]);
PUT_32BIT_LSB_FIRST(digest, 8, buf[2]);
PUT_32BIT_LSB_FIRST(digest, 12, buf[3]);
/* zero sensitive data */
/* notice this misses any sneaking out on the stack. The C
* version uses registers in some spots, perhaps because
* they care about this.
*/
Arrays.fill( in, (byte) 0 );
Arrays.fill( buf, 0 );
bits = 0;
}
/////////////////////////////////////////////////////////////////////
// Below here ye will only finde private functions //
/////////////////////////////////////////////////////////////////////
/**
* Zeros the given portion of the array
* @param a
* Array
* @param start
* start offset
* @param length
* how many bytes to zero
*/
private void zeroByteArray(
byte[] a,
int start,
int length)
{
setByteArray(a, (byte) 0, start, length);
}
/**
* Assigns a portion of the array to the given value
* @param a
* Array
* @param val
* value to assign
* @param start
* start offset
* @param length
* how many bytes to zero
*/
private void setByteArray(
byte[] a,
byte val,
int start,
int length)
{
int i;
int end = start + length;
for (i = start; i < end; i++)
{
a[i] = val;
}
}
/**
* MD5 main step
* @param w
* w
* @param x
* x
* @param y
* y
* @param z
* z
* @param data
* data
* @param s
* s
* @return
* step value
*/
private int MD5STEP1(
int w,
int x,
int y,
int z,
int data,
int s )
{
w += data + (z ^ (x & (y ^ z)));
return x + ((w << s) | (w >>> (32 - s)));
}
/**
* MD5 main step
* @param w
* w
* @param x
* x
* @param y
* y
* @param z
* z
* @param data
* data
* @param s
* s
* @return
* step value
*/
private int MD5STEP2(
int w,
int x,
int y,
int z,
int data,
int s )
{
w += data + (y ^ (z & (x ^ y)));
return x + ((w << s) | (w >>> (32 - s)));
}
/**
* MD5 main step
* @param w
* w
* @param x
* x
* @param y
* y
* @param z
* z
* @param data
* data
* @param s
* s
* @return
* step value
*/
private int MD5STEP3(
int w,
int x,
int y,
int z,
int data,
int s )
{
w += data + (x ^ y ^ z);
return x + ((w << s) | (w >>> (32 - s)));
}
/**
* MD5 main step
* @param w
* w
* @param x
* x
* @param y
* y
* @param z
* z
* @param data
* data
* @param s
* s
* @return
* step value
*/
private int MD5STEP4(
int w,
int x,
int y,
int z,
int data,
int s )
{
w += data + (y ^ (x | ~z));
return x + ((w << s) | (w >>> (32 - s)));
}
/**
* transforms the MD5 data
*/
private void transform()
{
final int ii00 = ((in[ 0] & 0xff) | ((in[ 1] & 0xff) << 8) | ((in[ 2] & 0xff) << 16) | ((in[ 3] & 0xff) << 24));
final int ii01 = ((in[ 4] & 0xff) | ((in[ 5] & 0xff) << 8) | ((in[ 6] & 0xff) << 16) | ((in[ 7] & 0xff) << 24));
final int ii02 = ((in[ 8] & 0xff) | ((in[ 9] & 0xff) << 8) | ((in[10] & 0xff) << 16) | ((in[11] & 0xff) << 24));
final int ii03 = ((in[12] & 0xff) | ((in[13] & 0xff) << 8) | ((in[14] & 0xff) << 16) | ((in[15] & 0xff) << 24));
final int ii04 = ((in[16] & 0xff) | ((in[17] & 0xff) << 8) | ((in[18] & 0xff) << 16) | ((in[19] & 0xff) << 24));
final int ii05 = ((in[20] & 0xff) | ((in[21] & 0xff) << 8) | ((in[22] & 0xff) << 16) | ((in[23] & 0xff) << 24));
final int ii06 = ((in[24] & 0xff) | ((in[25] & 0xff) << 8) | ((in[26] & 0xff) << 16) | ((in[27] & 0xff) << 24));
final int ii07 = ((in[28] & 0xff) | ((in[29] & 0xff) << 8) | ((in[30] & 0xff) << 16) | ((in[31] & 0xff) << 24));
final int ii08 = ((in[32] & 0xff) | ((in[33] & 0xff) << 8) | ((in[34] & 0xff) << 16) | ((in[35] & 0xff) << 24));
final int ii09 = ((in[36] & 0xff) | ((in[37] & 0xff) << 8) | ((in[38] & 0xff) << 16) | ((in[39] & 0xff) << 24));
final int ii10 = ((in[40] & 0xff) | ((in[41] & 0xff) << 8) | ((in[42] & 0xff) << 16) | ((in[43] & 0xff) << 24));
final int ii11 = ((in[44] & 0xff) | ((in[45] & 0xff) << 8) | ((in[46] & 0xff) << 16) | ((in[47] & 0xff) << 24));
final int ii12 = ((in[48] & 0xff) | ((in[49] & 0xff) << 8) | ((in[50] & 0xff) << 16) | ((in[51] & 0xff) << 24));
final int ii13 = ((in[52] & 0xff) | ((in[53] & 0xff) << 8) | ((in[54] & 0xff) << 16) | ((in[55] & 0xff) << 24));
final int ii14 = ((in[56] & 0xff) | ((in[57] & 0xff) << 8) | ((in[58] & 0xff) << 16) | ((in[59] & 0xff) << 24));
final int ii15 = ((in[60] & 0xff) | ((in[61] & 0xff) << 8) | ((in[62] & 0xff) << 16) | ((in[63] & 0xff) << 24));
int a = this.buf[0];
int b = this.buf[1];
int c = this.buf[2];
int d = this.buf[3];
a = MD5STEP1( a, b, c, d, ii00 + 0xd76aa478, 7);
d = MD5STEP1( d, a, b, c, ii01 + 0xe8c7b756, 12);
c = MD5STEP1( c, d, a, b, ii02 + 0x242070db, 17);
b = MD5STEP1( b, c, d, a, ii03 + 0xc1bdceee, 22);
a = MD5STEP1( a, b, c, d, ii04 + 0xf57c0faf, 7);
d = MD5STEP1( d, a, b, c, ii05 + 0x4787c62a, 12);
c = MD5STEP1( c, d, a, b, ii06 + 0xa8304613, 17);
b = MD5STEP1( b, c, d, a, ii07 + 0xfd469501, 22);
a = MD5STEP1( a, b, c, d, ii08 + 0x698098d8, 7);
d = MD5STEP1( d, a, b, c, ii09 + 0x8b44f7af, 12);
c = MD5STEP1( c, d, a, b, ii10 + 0xffff5bb1, 17);
b = MD5STEP1( b, c, d, a, ii11 + 0x895cd7be, 22);
a = MD5STEP1( a, b, c, d, ii12 + 0x6b901122, 7);
d = MD5STEP1( d, a, b, c, ii13 + 0xfd987193, 12);
c = MD5STEP1( c, d, a, b, ii14 + 0xa679438e, 17);
b = MD5STEP1( b, c, d, a, ii15 + 0x49b40821, 22);
a = MD5STEP2( a, b, c, d, ii01 + 0xf61e2562, 5);
d = MD5STEP2( d, a, b, c, ii06 + 0xc040b340, 9);
c = MD5STEP2( c, d, a, b, ii11 + 0x265e5a51, 14);
b = MD5STEP2( b, c, d, a, ii00 + 0xe9b6c7aa, 20);
a = MD5STEP2( a, b, c, d, ii05 + 0xd62f105d, 5);
d = MD5STEP2( d, a, b, c, ii10 + 0x02441453, 9);
c = MD5STEP2( c, d, a, b, ii15 + 0xd8a1e681, 14);
b = MD5STEP2( b, c, d, a, ii04 + 0xe7d3fbc8, 20);
a = MD5STEP2( a, b, c, d, ii09 + 0x21e1cde6, 5);
d = MD5STEP2( d, a, b, c, ii14 + 0xc33707d6, 9);
c = MD5STEP2( c, d, a, b, ii03 + 0xf4d50d87, 14);
b = MD5STEP2( b, c, d, a, ii08 + 0x455a14ed, 20);
a = MD5STEP2( a, b, c, d, ii13 + 0xa9e3e905, 5);
d = MD5STEP2( d, a, b, c, ii02 + 0xfcefa3f8, 9);
c = MD5STEP2( c, d, a, b, ii07 + 0x676f02d9, 14);
b = MD5STEP2( b, c, d, a, ii12 + 0x8d2a4c8a, 20);
a = MD5STEP3( a, b, c, d, ii05 + 0xfffa3942, 4);
d = MD5STEP3( d, a, b, c, ii08 + 0x8771f681, 11);
c = MD5STEP3( c, d, a, b, ii11 + 0x6d9d6122, 16);
b = MD5STEP3( b, c, d, a, ii14 + 0xfde5380c, 23);
a = MD5STEP3( a, b, c, d, ii01 + 0xa4beea44, 4);
d = MD5STEP3( d, a, b, c, ii04 + 0x4bdecfa9, 11);
c = MD5STEP3( c, d, a, b, ii07 + 0xf6bb4b60, 16);
b = MD5STEP3( b, c, d, a, ii10 + 0xbebfbc70, 23);
a = MD5STEP3( a, b, c, d, ii13 + 0x289b7ec6, 4);
d = MD5STEP3( d, a, b, c, ii00 + 0xeaa127fa, 11);
c = MD5STEP3( c, d, a, b, ii03 + 0xd4ef3085, 16);
b = MD5STEP3( b, c, d, a, ii06 + 0x04881d05, 23);
a = MD5STEP3( a, b, c, d, ii09 + 0xd9d4d039, 4);
d = MD5STEP3( d, a, b, c, ii12 + 0xe6db99e5, 11);
c = MD5STEP3( c, d, a, b, ii15 + 0x1fa27cf8, 16);
b = MD5STEP3( b, c, d, a, ii02 + 0xc4ac5665, 23);
a = MD5STEP4( a, b, c, d, ii00 + 0xf4292244, 6);
d = MD5STEP4( d, a, b, c, ii07 + 0x432aff97, 10);
c = MD5STEP4( c, d, a, b, ii14 + 0xab9423a7, 15);
b = MD5STEP4( b, c, d, a, ii05 + 0xfc93a039, 21);
a = MD5STEP4( a, b, c, d, ii12 + 0x655b59c3, 6);
d = MD5STEP4( d, a, b, c, ii03 + 0x8f0ccc92, 10);
c = MD5STEP4( c, d, a, b, ii10 + 0xffeff47d, 15);
b = MD5STEP4( b, c, d, a, ii01 + 0x85845dd1, 21);
a = MD5STEP4( a, b, c, d, ii08 + 0x6fa87e4f, 6);
d = MD5STEP4( d, a, b, c, ii15 + 0xfe2ce6e0, 10);
c = MD5STEP4( c, d, a, b, ii06 + 0xa3014314, 15);
b = MD5STEP4( b, c, d, a, ii13 + 0x4e0811a1, 21);
a = MD5STEP4( a, b, c, d, ii04 + 0xf7537e82, 6);
d = MD5STEP4( d, a, b, c, ii11 + 0xbd3af235, 10);
c = MD5STEP4( c, d, a, b, ii02 + 0x2ad7d2bb, 15);
b = MD5STEP4( b, c, d, a, ii09 + 0xeb86d391, 21);
this.buf[0] += a;
this.buf[1] += b;
this.buf[2] += c;
this.buf[3] += d;
}
/**
* Sets the LSB fist
* @param b
* bytes
* @param off
* offset
* @param value
* LSB value
*/
private void PUT_32BIT_LSB_FIRST(
byte[] b,
int off,
int value)
{
b[off + 0] = (byte) (value);
b[off + 1] = (byte) (value >>> 8);
b[off + 2] = (byte) (value >>> 16);
b[off + 3] = (byte) (value >>> 24);
}
}