Programming Forums
User Name Password Register
 

RSS Feed
FORUM INDEX | TODAY'S POSTS | UNANSWERED THREADS | ADVANCED SEARCH

Reply
 
Thread Tools Display Modes
Old Aug 2nd, 2006, 5:01 PM   #1
grimpirate
King of Portal
 
grimpirate's Avatar
 
Join Date: Sep 2005
Posts: 439
Rep Power: 4 grimpirate is on a distinguished road
Send a message via Yahoo to grimpirate
Exclamation Trouble with an MD5 implementation

Well I recently made a small md5 hash calculator program and posted it on the finished projects section. However, upon reading some replies Sane said that perhaps I should try implementing it myself, and so I did. However, I'm unsure why my implementation isn't working. Here's the code, it's two java classes, a driver called MD5Test and the MD5 class:

MD5.java
public class MD5
{
	private static final int[] T = new int[64];

	public MD5()
	{
		int i = 0;
		T[i++] = 0xd76aa478;
		T[i++] = 0xe8c7b756;
		T[i++] = 0x242070db;
		T[i++] = 0xc1bdceee;
		T[i++] = 0xf57c0faf;
		T[i++] = 0x4787c62a;
		T[i++] = 0xa8304613;
		T[i++] = 0xfd469501;
		T[i++] = 0x698098d8;
		T[i++] = 0x8b44f7af;
		T[i++] = 0xffff5bb1;
		T[i++] = 0x895cd7be;
		T[i++] = 0x6b901122;
		T[i++] = 0xfd987193;
		T[i++] = 0xa679438e;
		T[i++] = 0x49b40821;
		T[i++] = 0xf61e2562;
		T[i++] = 0xc040b340;
		T[i++] = 0x265e5a51;
		T[i++] = 0xe9b6c7aa;
		T[i++] = 0xd62f105d;
		T[i++] = 0x2441453;
		T[i++] = 0xd8a1e681;
		T[i++] = 0xe7d3fbc8;
		T[i++] = 0x21e1cde6;
		T[i++] = 0xc33707d6;
		T[i++] = 0xf4d50d87;
		T[i++] = 0x455a14ed;
		T[i++] = 0xa9e3e905;
		T[i++] = 0xfcefa3f8;
		T[i++] = 0x676f02d9;
		T[i++] = 0x8d2a4c8a;
		T[i++] = 0xfffa3942;
		T[i++] = 0x8771f681;
		T[i++] = 0x6d9d6122;
		T[i++] = 0xfde5380c;
		T[i++] = 0xa4beea44;
		T[i++] = 0x4bdecfa9;
		T[i++] = 0xf6bb4b60;
		T[i++] = 0xbebfbc70;
		T[i++] = 0x289b7ec6;
		T[i++] = 0xeaa127fa;
		T[i++] = 0xd4ef3085;
		T[i++] = 0x4881d05;
		T[i++] = 0xd9d4d039;
		T[i++] = 0xe6db99e5;
		T[i++] = 0x1fa27cf8;
		T[i++] = 0xc4ac5665;
		T[i++] = 0xf4292244;
		T[i++] = 0x432aff97;
		T[i++] = 0xab9423a7;
		T[i++] = 0xfc93a039;
		T[i++] = 0x655b59c3;
		T[i++] = 0x8f0ccc92;
		T[i++] = 0xffeff47d;
		T[i++] = 0x85845dd1;
		T[i++] = 0x6fa87e4f;
		T[i++] = 0xfe2ce6e0;
		T[i++] = 0xa3014314;
		T[i++] = 0x4e0811a1;
		T[i++] = 0xf7537e82;
		T[i++] = 0xbd3af235;
		T[i++] = 0x2ad7d2bb;
		T[i++] = 0xeb86d391;
	}

	public String hash()
	{
		int A = 0x67452301;
		int B = 0xefcdab89;
		int C = 0x98badcfe;
		int D = 0x10325476;

		int[] M = new int[16];
		int[] X = new int[16];

		// A message of no length
		// Starts here
		M[0] = 0x80000000;

		for(int i = 1; i < M.length; i++)
		{
			M[i] = 0;
		}
		// Ends here

		for(int i = 0; i < M.length / 16; i++)
		{
			for(int j = 0; j < 16; j++)
			{
				X[j] = M[i * 16 + j];
			}

			int AA = A;
			int BB = B;
			int CC = C;
			int DD = D;

			A = round1(A, B, C, D, X[0], 7, 1 - 1);
			D = round1(D, A, B, C, X[1], 12, 2 - 1);
			C = round1(C, D, A, B, X[2], 17, 3 - 1);
			B = round1(B, C, D, A, X[3], 22, 4 - 1);
			A = round1(A, B, C, D, X[4], 7, 5 - 1);
			D = round1(D, A, B, C, X[5], 12, 6 - 1);
			C = round1(C, D, A, B, X[6], 17, 7 - 1);
			B = round1(B, C, D, A, X[7], 22, 8 - 1);
			A = round1(A, B, C, D, X[8], 7, 9 - 1 );
			D = round1(D, A, B, C, X[9], 12, 10 - 1);
			C = round1(C, D, A, B, X[10], 17, 11 - 1);
			B = round1(B, C, D, A, X[11], 22, 12 - 1);
			A = round1(A, B, C, D, X[12], 7, 13 - 1);
			D = round1(D, A, B, C, X[13], 12, 14 - 1);
			C = round1(C, D, A, B, X[14], 17, 15 - 1);
			B = round1(B, C, D, A, X[15], 22, 16 - 1);
			A = round2(A, B, C, D, X[1], 5, 17 - 1);
			D = round2(D, A, B, C, X[6], 9, 18 - 1);
			C = round2(C, D, A, B, X[11], 14, 19 - 1);
			B = round2(B, C, D, A, X[0], 20, 20 - 1);
			A = round2(A, B, C, D, X[5], 5, 21 - 1);
			D = round2(D, A, B, C, X[10], 9, 22 - 1);
			C = round2(C, D, A, B, X[15], 14, 23 - 1);
			B = round2(B, C, D, A, X[4], 20, 24 - 1);
			A = round2(A, B, C, D, X[9], 5, 25 - 1);
			D = round2(D, A, B, C, X[14], 9, 26 - 1);
			C = round2(C, D, A, B, X[3], 14, 27 - 1);
			B = round2(B, C, D, A, X[8], 20, 28 - 1);
			A = round2(A, B, C, D, X[13], 5, 29 - 1);
			D = round2(D, A, B, C, X[2], 9, 30 - 1);
			C = round2(C, D, A, B, X[7], 14, 31 - 1);
			B = round2(B, C, D, A, X[12], 20, 32 - 1);
			A = round3(A, B, C, D, X[5], 4, 33 - 1);
			D = round3(D, A, B, C, X[8], 11, 34 - 1);
			C = round3(C, D, A, B, X[11], 16, 35 - 1);
			B = round3(B, C, D, A, X[14], 23, 36 - 1);
			A = round3(A, B, C, D, X[1], 4, 37 - 1);
			D = round3(D, A, B, C, X[4], 11, 38 - 1);
			C = round3(C, D, A, B, X[7], 16, 39 - 1);
			B = round3(B, C, D, A, X[10], 23, 40 - 1);
			A = round3(A, B, C, D, X[13], 4, 41 - 1);
			D = round3(D, A, B, C, X[0], 11, 42 - 1);
			C = round3(C, D, A, B, X[3], 16, 43 - 1);
			B = round3(B, C, D, A, X[6], 23, 44 - 1);
			A = round3(A, B, C, D, X[9], 4, 45 - 1);
			D = round3(D, A, B, C, X[12], 11, 46 - 1);
			C = round3(C, D, A, B, X[15], 16, 47 - 1);
			B = round3(B, C, D, A, X[2], 23, 48 - 1);
			A = round4(A, B, C, D, X[0], 6, 49 - 1);
			D = round4(D, A, B, C, X[7], 10, 50 - 1);
			C = round4(C, D, A, B, X[14], 15, 51 - 1);
			B = round4(B, C, D, A, X[5], 21, 52 - 1);
			A = round4(A, B, C, D, X[12], 6, 53 - 1);
			D = round4(D, A, B, C, X[3], 10, 54 - 1);
			C = round4(C, D, A, B, X[10], 15, 55 - 1);
			B = round4(B, C, D, A, X[1], 21, 56 - 1);
			A = round4(A, B, C, D, X[8], 6, 57 - 1);
			D = round4(D, A, B, C, X[15], 10, 58 - 1);
			C = round4(C, D, A, B, X[6], 15, 59 - 1);
			B = round4(B, C, D, A, X[13], 21, 60 - 1);
			A = round4(A, B, C, D, X[4], 6, 61 - 1);
			D = round4(D, A, B, C, X[11], 10, 62 - 1);
			C = round4(C, D, A, B, X[2], 15, 63 - 1);
			B = round4(B, C, D, A, X[9], 21, 64 - 1);

			A += AA;
			B += BB;
			C += CC;
			D += DD;
		}

		return Integer.toHexString(A) + Integer.toHexString(B) + Integer.toHexString(C) + Integer.toHexString(D);
	}

	private int round1(int a, int b, int c, int d, int x, int s, int i)
	{
		return b + lShiftRotate((a + F(b, c, d) + x + T[i]), s);
	}

	private int round2(int a, int b, int c, int d, int x, int s, int i)
	{
		return b + lShiftRotate((a + G(b, c, d) + x + T[i]), s);
	}

	private int round3(int a, int b, int c, int d, int x, int s, int i)
	{
		return b + lShiftRotate((a + H(b, c, d) + x + T[i]), s);
	}

	private int round4(int a, int b, int c, int d, int x, int s, int i)
	{
		return b + lShiftRotate((a + I(b, c, d) + x + T[i]), s);
	}

	private int F(int X, int Y, int Z)
	{
		return X & Y | ~X & Z;
	}

	private int G(int X, int Y, int Z)
	{
		return X & Z | Y & ~Z;
	}

	private int H(int X, int Y, int Z)
	{
		return X ^ Y ^ Z;
	}

	private int I(int X, int Y, int Z)
	{
		return Y ^ (X | ~Z);
	}

	public static int lShiftRotate(int x, int y)
	{
		int mask = 0x80000000;

		for(int i = 0; i < y; i++)
		{
			if((x & mask) == 0)
			{
				x = x << 1;
			}
			else
			{
				x = (x << 1) + 1;
			}
		}

		return x;
	}
}
MD5Test.java
public class MD5Test
{
	public static void main(String[] args)
	{
		MD5 message = new MD5();
		System.out.println(message.hash());
	}
}
Right now the program is only supposed to compute the has/checksum of an empty string/file or whatever. It's the array listed as M, which is originally 0 but as I understand it, if a message has 0 length then it should start with a 1 and follow with 511 0's, which is what I did there to the best of my knowledge. I'm not sure whether or not A, B, C, and D are their proper values as there's some reference to big-endian or little-endian notation and I'm unsure as how to proceed. I copied the values from the RFC reference implementation, as well as the values for T which are supposed to be obtainable by performing a calculation along the lines of Math.floor(Math.abs(Math.sin(i)) * Math.pow(2, 32)) where {i: 1...64}, buuuuuuuuuuut those values weren't anywhere even remotely close when I actually computed it to the hex values given in the reference implementation. If anybody could point out where I have an error, or for that matter a series of cascading errors lol, I'd appreciate it.

P.S. As stated in the RFC the hash for a string of "" should be
MD5 ("") = d41d8cd98f00b204e9800998ecf8427e
__________________
Lo, there do I see my father. 'Lo, there do I see My mother, and my sisters, and my brothers. 'Lo, there do I see The line of my people... Back to the beginning. 'Lo, they do call to me. They bid me take my place among them. In the halls of Valhalla... Where the brave... May live... ...forever.. GrimBB | Mimesis
grimpirate is offline   Reply With Quote
Old Aug 2nd, 2006, 5:49 PM   #2
grimpirate
King of Portal
 
grimpirate's Avatar
 
Join Date: Sep 2005
Posts: 439
Rep Power: 4 grimpirate is on a distinguished road
Send a message via Yahoo to grimpirate
uhh... yeah I typed in those values for nothing in the constructor 'cause I actually figured out how to work the formula, anyways here's how to determine the values of T according to the stipulation in the RFC:
	public MD5()
	{
		for(int i = 0; i < T.length; i++)
		{
			double temp = Math.abs(Math.sin(i + 1)) * Math.pow(2, 32);
			if(temp > Math.pow(2, 32) / 2 - 1)
			{
				T[i] = (int)Math.floor(temp - Math.pow(2, 32));
			}
			else
			{
				T[i] = (int)Math.floor(temp);
			}
		}
	}
That's what the constructor should look like, which betters the code visually I suppose, but I assume it also slows down the program since having the values readily available take less clock cycles. I leave it to you to choose which one you like. I'm sure there's also an easier way than the one that I chose, some sort of casting using a long of some sort.
grimpirate is offline   Reply With Quote
Old Aug 2nd, 2006, 11:02 PM   #3
DaWei
Resident Grouch
 
DaWei's Avatar
 
Join Date: Jun 2005
Posts: 6,453
Rep Power: 10 DaWei is on a distinguished road
No wonder pirates are grim.
__________________
Abstraction doesn't make it impossible to write bad code; it makes it possible to write superior code.
Contributor's Corner: Grumpy on C++ Exceptions DaWei on Pointers
DaWei is offline   Reply With Quote
Old Aug 3rd, 2006, 12:36 AM   #4
grimpirate
King of Portal
 
grimpirate's Avatar
 
Join Date: Sep 2005
Posts: 439
Rep Power: 4 grimpirate is on a distinguished road
Send a message via Yahoo to grimpirate
The C is a harsh mistress. That's why we drink plenty of Java. ahahaha
__________________
Lo, there do I see my father. 'Lo, there do I see My mother, and my sisters, and my brothers. 'Lo, there do I see The line of my people... Back to the beginning. 'Lo, they do call to me. They bid me take my place among them. In the halls of Valhalla... Where the brave... May live... ...forever.. GrimBB | Mimesis
grimpirate is offline   Reply With Quote
Old Aug 3rd, 2006, 12:43 AM   #5
AntiNinja
Hobbyist Programmer
 
AntiNinja's Avatar
 
Join Date: Jun 2006
Location: The States
Posts: 101
Rep Power: 3 AntiNinja is on a distinguished road
Send a message via AIM to AntiNinja Send a message via Yahoo to AntiNinja
Quote:
Originally Posted by grimpirate
The C is a harsh mistress. That's why we drink plenty of Java.
__________________
Pain is just weakness leaving the body.
AntiNinja is offline   Reply With Quote
Old Aug 4th, 2006, 3:23 PM   #6
grimpirate
King of Portal
 
grimpirate's Avatar
 
Join Date: Sep 2005
Posts: 439
Rep Power: 4 grimpirate is on a distinguished road
Send a message via Yahoo to grimpirate
Breakthrough!

yes I discovered what the problem was with my code. As it turns out the implementation was correct there were no little tiny errors or anything. However, what happens is that Rivest fails to mention in the RFC that input is assumed to be in a little-endian format and therefore needs to be decoded into big-endian format. Furthermore, the outputs A, B, C, and D are in little-endian format and need to be output into big-endian format. Why did he do this? I have no idea but as far as I'm concerned the man's an idiot, especially since it just seems to be wasting clock cycles. In my code you'll note the two major changes: the array value's inital value M[0] is now 0x00000080 instead of 0x80000000 and I added a function called encode which transforms from little-endian into big-endian. This is also why the values of A, B, C, and D, when initialized look mirrored to how they are written in the RFC. Here's the updated MD5 class
MD5.java
import java.lang.Math;

public class MD5
{
	private static int[] T = new int[64];

	public MD5()
	{
		for(int i = 0; i < T.length; i++)
		{
			double temp = Math.abs(Math.sin(i + 1)) * Math.pow(2, 32);
			if(temp > Math.pow(2, 32) / 2 - 1)
			{
				T[i] = (int)Math.floor(temp - Math.pow(2, 32));
			}
			else
			{
				T[i] = (int)Math.floor(temp);
			}
		}
	}

	public String hash()
	{
		int A = 0x67452301;
		int B = 0xefcdab89;
		int C = 0x98badcfe;
		int D = 0x10325476;

		int[] M = new int[16];
		int[] X = new int[16];

		// A message of no length
		// Starts here

		// This was reversed because the input is supposed to come in little-endian format
		// while computations are performed in a big-endian style
		M[0] = 0x00000080;

		for(int i = 1; i < M.length; i++)
		{
			M[i] = 0;
		}
		// Ends here

		for(int i = 0; i < M.length / X.length; i++)
		{
			for(int j = 0; j < X.length; j++)
			{
				X[j] = M[i * 16 + j];
			}

			int AA = A;
			int BB = B;
			int CC = C;
			int DD = D;

			A = round1(A, B, C, D, X[0], 7, 1 - 1);
			D = round1(D, A, B, C, X[1], 12, 2 - 1);
			C = round1(C, D, A, B, X[2], 17, 3 - 1);
			B = round1(B, C, D, A, X[3], 22, 4 - 1);

			A = round1(A, B, C, D, X[4], 7, 5 - 1);
			D = round1(D, A, B, C, X[5], 12, 6 - 1);
			C = round1(C, D, A, B, X[6], 17, 7 - 1);
			B = round1(B, C, D, A, X[7], 22, 8 - 1);

			A = round1(A, B, C, D, X[8], 7, 9 - 1 );
			D = round1(D, A, B, C, X[9], 12, 10 - 1);
			C = round1(C, D, A, B, X[10], 17, 11 - 1);
			B = round1(B, C, D, A, X[11], 22, 12 - 1);

			A = round1(A, B, C, D, X[12], 7, 13 - 1);
			D = round1(D, A, B, C, X[13], 12, 14 - 1);
			C = round1(C, D, A, B, X[14], 17, 15 - 1);
			B = round1(B, C, D, A, X[15], 22, 16 - 1);

			A = round2(A, B, C, D, X[1], 5, 17 - 1);
			D = round2(D, A, B, C, X[6], 9, 18 - 1);
			C = round2(C, D, A, B, X[11], 14, 19 - 1);
			B = round2(B, C, D, A, X[0], 20, 20 - 1);

			A = round2(A, B, C, D, X[5], 5, 21 - 1);
			D = round2(D, A, B, C, X[10], 9, 22 - 1);
			C = round2(C, D, A, B, X[15], 14, 23 - 1);
			B = round2(B, C, D, A, X[4], 20, 24 - 1);

			A = round2(A, B, C, D, X[9], 5, 25 - 1);
			D = round2(D, A, B, C, X[14], 9, 26 - 1);
			C = round2(C, D, A, B, X[3], 14, 27 - 1);
			B = round2(B, C, D, A, X[8], 20, 28 - 1);

			A = round2(A, B, C, D, X[13], 5, 29 - 1);
			D = round2(D, A, B, C, X[2], 9, 30 - 1);
			C = round2(C, D, A, B, X[7], 14, 31 - 1);
			B = round2(B, C, D, A, X[12], 20, 32 - 1);

			A = round3(A, B, C, D, X[5], 4, 33 - 1);
			D = round3(D, A, B, C, X[8], 11, 34 - 1);
			C = round3(C, D, A, B, X[11], 16, 35 - 1);
			B = round3(B, C, D, A, X[14], 23, 36 - 1);

			A = round3(A, B, C, D, X[1], 4, 37 - 1);
			D = round3(D, A, B, C, X[4], 11, 38 - 1);
			C = round3(C, D, A, B, X[7], 16, 39 - 1);
			B = round3(B, C, D, A, X[10], 23, 40 - 1);

			A = round3(A, B, C, D, X[13], 4, 41 - 1);
			D = round3(D, A, B, C, X[0], 11, 42 - 1);
			C = round3(C, D, A, B, X[3], 16, 43 - 1);
			B = round3(B, C, D, A, X[6], 23, 44 - 1);

			A = round3(A, B, C, D, X[9], 4, 45 - 1);
			D = round3(D, A, B, C, X[12], 11, 46 - 1);
			C = round3(C, D, A, B, X[15], 16, 47 - 1);
			B = round3(B, C, D, A, X[2], 23, 48 - 1);

			A = round4(A, B, C, D, X[0], 6, 49 - 1);
			D = round4(D, A, B, C, X[7], 10, 50 - 1);
			C = round4(C, D, A, B, X[14], 15, 51 - 1);
			B = round4(B, C, D, A, X[5], 21, 52 - 1);

			A = round4(A, B, C, D, X[12], 6, 53 - 1);
			D = round4(D, A, B, C, X[3], 10, 54 - 1);
			C = round4(C, D, A, B, X[10], 15, 55 - 1);
			B = round4(B, C, D, A, X[1], 21, 56 - 1);

			A = round4(A, B, C, D, X[8], 6, 57 - 1);
			D = round4(D, A, B, C, X[15], 10, 58 - 1);
			C = round4(C, D, A, B, X[6], 15, 59 - 1);
			B = round4(B, C, D, A, X[13], 21, 60 - 1);

			A = round4(A, B, C, D, X[4], 6, 61 - 1);
			D = round4(D, A, B, C, X[11], 10, 62 - 1);
			C = round4(C, D, A, B, X[2], 15, 63 - 1);
			B = round4(B, C, D, A, X[9], 21, 64 - 1);

			A += AA;
			B += BB;
			C += CC;
			D += DD;
		}

		return Integer.toHexString(encode(A)) + Integer.toHexString(encode(B)) + Integer.toHexString(encode(C)) + Integer.toHexString(encode(D));
	}

	private int round1(int a, int b, int c, int d, int x, int s, int i)
	{
		return b + Integer.rotateLeft((a + F(b, c, d) + x + T[i]), s);
	}

	private int round2(int a, int b, int c, int d, int x, int s, int i)
	{
		return b + Integer.rotateLeft((a + G(b, c, d) + x + T[i]), s);
	}

	private int round3(int a, int b, int c, int d, int x, int s, int i)
	{
		return b + Integer.rotateLeft((a + H(b, c, d) + x + T[i]), s);
	}

	private int round4(int a, int b, int c, int d, int x, int s, int i)
	{
		return b + Integer.rotateLeft((a + I(b, c, d) + x + T[i]), s);
	}

	private int F(int X, int Y, int Z)
	{
		return X & Y | ~X & Z;
	}

	private int G(int X, int Y, int Z)
	{
		return X & Z | Y & ~Z;
	}

	private int H(int X, int Y, int Z)
	{
		return X ^ Y ^ Z;
	}

	private int I(int X, int Y, int Z)
	{
		return Y ^ (X | ~Z);
	}

	// This method converts an input from little-endian into big-endian
	private int encode(int x)
	{
		int mask[] = new int[4];

		mask[0] = 0xff000000;
		mask[1] = 0x00ff0000;
		mask[2] = 0x0000ff00;
		mask[3] = 0x000000ff;

		return Integer.rotateRight(x & mask[0], 24) + Integer.rotateRight(x & mask[1], 8) + Integer.rotateLeft(x & mask[2], 8) + Integer.rotateLeft(x & mask[3], 24);
	}
}
I'll keep posting whatever advancements I make with it. Like accepting InputStreams or strings or whatever. But for now it at least produces the correct output for an input of no length. Pirates rule!
__________________
Lo, there do I see my father. 'Lo, there do I see My mother, and my sisters, and my brothers. 'Lo, there do I see The line of my people... Back to the beginning. 'Lo, they do call to me. They bid me take my place among them. In the halls of Valhalla... Where the brave... May live... ...forever.. GrimBB | Mimesis
grimpirate is offline   Reply With Quote
Old Aug 4th, 2006, 4:13 PM   #7
Infinite Recursion
Programming Guru
 
Infinite Recursion's Avatar
 
Join Date: Jul 2004
Location: United States
Posts: 3,473
Rep Power: 8 Infinite Recursion is on a distinguished road
Send a message via MSN to Infinite Recursion Send a message via Yahoo to Infinite Recursion
[aside]
"Pirates rule!"

Today was deemed "Pirate's Day" by my employer. The upper management dressed up as pirates and came around the offices (aka Cubevile, aka Dilbertville) handing out "stolen treasure".... I threw all of the crap aside to try and find the gold, but no gold and no check... Management needs to learn how to code, they have too much free time on their hands... bah.

[/aside]
__________________
http://jasonpowers.net

"There are a thousand hacking at the branches of evil to one who is striking at the root."
Infinite Recursion is offline   Reply With Quote
Old Aug 8th, 2006, 5:52 AM   #8
grimpirate
King of Portal
 
grimpirate's Avatar
 
Join Date: Sep 2005
Posts: 439
Rep Power: 4 grimpirate is on a distinguished road
Send a message via Yahoo to grimpirate
Well I got it to accept bytes, so to all you programmers out there please try as many different strings as you can come up with and lemme know if they produce the wrong output, assuming you care to that is. I tried it out with Rivest's test suite and it worked fine and with some of my own so I'm gonna say it's working. Here are the two classes again:
MD5.java
import java.lang.Math;

public class MD5
{
	private int[] T = new int[64];

	private int A = 0x67452301;
	private	int B = 0xefcdab89;
	private	int C = 0x98badcfe;
	private int D = 0x10325476;

	private long bytesTransferred = 0;
	private int bytesSwitch = 0;

	private int[] X;

	private int entrySwitch = 0;

	private int transferredWord = 0;

	public MD5()
	{
		for(int i = 0; i < T.length; i++)
		{
			double temp = Math.abs(Math.sin(i + 1)) * Math.pow(2, 32);
			if(temp > Math.pow(2, 32) / 2 - 1)
			{
				T[i] = (int)Math.floor(temp - Math.pow(2, 32));
			}
			else
			{
				T[i] = (int)Math.floor(temp);
			}
		}

		X = new int[16];
	}

	public void update(byte chunk)
	{
		bytesTransferred++;
		bytesSwitch++;

		int temp = 0;

		switch(bytesSwitch)
		{
			case 1:
				temp = chunk & 0x000000ff;
				break;
			case 2:
				temp = chunk & 0x000000ff;
				temp = temp << 8;
				break;
			case 3:
				temp = chunk & 0x000000ff;
				temp = temp << 16;
				break;
			case 4:
				temp = chunk & 0x000000ff;
				temp = temp << 24;
				break;
		}

		transferredWord = transferredWord ^ temp;
		if(bytesSwitch == 4)
		{
			bytesSwitch = 0;
			X[entrySwitch] = transferredWord;
			entrySwitch++;
			transferredWord = 0;
		}

//		int[] M = new int[16];

		// A message of no length
		// Starts here

		// This was reversed because the input is supposed to come in little-endian format
		// while computations are performed in a big-endian style
//		M[0] = 0x80636261;	// "abc"
//		M[1] = 0;
//		M[2] = 0;
//		M[3] = 0;
//		M[4] = 0;
//		M[5] = 0;
//		M[6] = 0;
//		M[7] = 0;
//		M[8] = 0;
//		M[9] = 0;
//		M[10] = 0;
//		M[11] = 0;
//		M[12] = 0;
//		M[13] = 0;
//		M[14] = 0x00000018;
//		M[15] = 0x00000000;
		// Ends here

//		for(int i = 0; i < M.length / X.length; i++)
//		{
//			for(int j = 0; j < X.length; j++)
//			{
//				X[j] = M[i * 16 + j];
//			}
		if(entrySwitch == 16)
		{
			entrySwitch = 0;

			int AA = A;
			int BB = B;
			int CC = C;
			int DD = D;

			A = round1(A, B, C, D, X[0], 7, 1 - 1);
			D = round1(D, A, B, C, X[1], 12, 2 - 1);
			C = round1(C, D, A, B, X[2], 17, 3 - 1);
			B = round1(B, C, D, A, X[3], 22, 4 - 1);

			A = round1(A, B, C, D, X[4], 7, 5 - 1);
			D = round1(D, A, B, C, X[5], 12, 6 - 1);
			C = round1(C, D, A, B, X[6], 17, 7 - 1);
			B = round1(B, C, D, A, X[7], 22, 8 - 1);

			A = round1(A, B, C, D, X[8], 7, 9 - 1 );
			D = round1(D, A, B, C, X[9], 12, 10 - 1);
			C = round1(C, D, A, B, X[10], 17, 11 - 1);
			B = round1(B, C, D, A, X[11], 22, 12 - 1);

			A = round1(A, B, C, D, X[12], 7, 13 - 1);
			D = round1(D, A, B, C, X[13], 12, 14 - 1);
			C = round1(C, D, A, B, X[14], 17, 15 - 1);
			B = round1(B, C, D, A, X[15], 22, 16 - 1);

			A = round2(A, B, C, D, X[1], 5, 17 - 1);
			D = round2(D, A, B, C, X[6], 9, 18 - 1);
			C = round2(C, D, A, B, X[11], 14, 19 - 1);
			B = round2(B, C, D, A, X[0], 20, 20 - 1);

			A = round2(A, B, C, D, X[5], 5, 21 - 1);
			D = round2(D, A, B, C, X[10], 9, 22 - 1);
			C = round2(C, D, A, B, X[15], 14, 23 - 1);
			B = round2(B, C, D, A, X[4], 20, 24 - 1);

			A = round2(A, B, C, D, X[9], 5, 25 - 1);
			D = round2(D, A, B, C, X[14], 9, 26 - 1);
			C = round2(C, D, A, B, X[3], 14, 27 - 1);
			B = round2(B, C, D, A, X[8], 20, 28 - 1);

			A = round2(A, B, C, D, X[13], 5, 29 - 1);
			D = round2(D, A, B, C, X[2], 9, 30 - 1);
			C = round2(C, D, A, B, X[7], 14, 31 - 1);
			B = round2(B, C, D, A, X[12], 20, 32 - 1);

			A = round3(A, B, C, D, X[5], 4, 33 - 1);
			D = round3(D, A, B, C, X[8], 11, 34 - 1);
			C = round3(C, D, A, B, X[11], 16, 35 - 1);
			B = round3(B, C, D, A, X[14], 23, 36 - 1);

			A = round3(A, B, C, D, X[1], 4, 37 - 1);
			D = round3(D, A, B, C, X[4], 11, 38 - 1);
			C = round3(C, D, A, B, X[7], 16, 39 - 1);
			B = round3(B, C, D, A, X[10], 23, 40 - 1);

			A = round3(A, B, C, D, X[13], 4, 41 - 1);
			D = round3(D, A, B, C, X[0], 11, 42 - 1);
			C = round3(C, D, A, B, X[3], 16, 43 - 1);
			B = round3(B, C, D, A, X[6], 23, 44 - 1);

			A = round3(A, B, C, D, X[9], 4, 45 - 1);
			D = round3(D, A, B, C, X[12], 11, 46 - 1);
			C = round3(C, D, A, B, X[15], 16, 47 - 1);
			B = round3(B, C, D, A, X[2], 23, 48 - 1);

			A = round4(A, B, C, D, X[0], 6, 49 - 1);
			D = round4(D, A, B, C, X[7], 10, 50 - 1);
			C = round4(C, D, A, B, X[14], 15, 51 - 1);
			B = round4(B, C, D, A, X[5], 21, 52 - 1);

			A = round4(A, B, C, D, X[12], 6, 53 - 1);
			D = round4(D, A, B, C, X[3], 10, 54 - 1);
			C = round4(C, D, A, B, X[10], 15, 55 - 1);
			B = round4(B, C, D, A, X[1], 21, 56 - 1);

			A = round4(A, B, C, D, X[8], 6, 57 - 1);
			D = round4(D, A, B, C, X[15], 10, 58 - 1);
			C = round4(C, D, A, B, X[6], 15, 59 - 1);
			B = round4(B, C, D, A, X[13], 21, 60 - 1);

			A = round4(A, B, C, D, X[4], 6, 61 - 1);
			D = round4(D, A, B, C, X[11], 10, 62 - 1);
			C = round4(C, D, A, B, X[2], 15, 63 - 1);
			B = round4(B, C, D, A, X[9], 21, 64 - 1);

			A += AA;
			B += BB;
			C += CC;
			D += DD;
		}
	}

	public String finish()
	{
		long fileSize = bytesTransferred * 8;	// in bits
		byte sizePad[] = new byte[8];

		sizePad[0] = (byte)(fileSize & 0x00000000000000ffL);
		sizePad[1] = (byte)((fileSize >> 8) & 0x00000000000000ffL);
		sizePad[2] = (byte)((fileSize >> 16) & 0x00000000000000ffL);
		sizePad[3] = (byte)((fileSize >> 24) & 0x00000000000000ffL);
		sizePad[4] = (byte)((fileSize >> 32) & 0x00000000000000ffL);
		sizePad[5] = (byte)((fileSize >> 40) & 0x00000000000000ffL);
		sizePad[6] = (byte)((fileSize >> 48) & 0x00000000000000ffL);
		sizePad[7] = (byte)((fileSize >> 56) & 0x00000000000000ffL);

		update((byte)0x80);

		long incongruent = bytesTransferred % 64;

		if(incongruent < 57)
		{
			for(long i = incongruent; i < 56; i++)
			{
				update((byte)0x00);
			}
		}
		else
		{
			for(long i = incongruent; i < 64; i++)
			{
				update((byte)0x00);
			}
			for(int i = 0; i < 56; i++)
			{
				update((byte)0x00);
			}
		}

		for(int i = 0; i < sizePad.length; i++)
		{
			update(sizePad[i]);
		}

		return parseHash();
	}

	private String parseHash()
	{
		String part[] = new String[4];

		part[0] = Integer.toHexString(encode(A));
		part[1] = Integer.toHexString(encode(B));
		part[2] = Integer.toHexString(encode(C));
		part[3] = Integer.toHexString(encode(D));

		for(int j = 0; j < part.length; j++)
		{
			for(int i = 0; i < 8 - part[j].length(); i++)
			{
				part[j] = "0" + part[j];
			}
		}

		return part[0] + part[1] + part[2] + part[3];
	}

	private int round1(int a, int b, int c, int d, int x, int s, int i)
	{
		return b + Integer.rotateLeft((a + F(b, c, d) + x + T[i]), s);
	}

	private int round2(int a, int b, int c, int d, int x, int s, int i)
	{
		return b + Integer.rotateLeft((a + G(b, c, d) + x + T[i]), s);
	}

	private int round3(int a, int b, int c, int d, int x, int s, int i)
	{
		return b + Integer.rotateLeft((a + H(b, c, d) + x + T[i]), s);
	}

	private int round4(int a, int b, int c, int d, int x, int s, int i)
	{
		return b + Integer.rotateLeft((a + I(b, c, d) + x + T[i]), s);
	}

	private int F(int X, int Y, int Z)
	{
		return X & Y | ~X & Z;
	}

	private int G(int X, int Y, int Z)
	{
		return X & Z | Y & ~Z;
	}

	private int H(int X, int Y, int Z)
	{
		return X ^ Y ^ Z;
	}

	private int I(int X, int Y, int Z)
	{
		return Y ^ (X | ~Z);
	}

	// This method converts an input from little-endian into big-endian
	private int encode(int x)
	{
		int mask[] = new int[4];

		mask[0] = 0xff000000;
		mask[1] = 0x00ff0000;
		mask[2] = 0x0000ff00;
		mask[3] = 0x000000ff;

		return Integer.rotateRight(x & mask[0], 24) + Integer.rotateRight(x & mask[1], 8) + Integer.rotateLeft(x & mask[2], 8) + Integer.rotateLeft(x & mask[3], 24);
	}
}
And its driver:
MD5Test.java
import java.lang.Math;
public class MD5Test
{
	public static void main(String[] args)
	{
		MD5 message = new MD5();
		String foo = new String("a"); // Place test string here
		byte bar[] = foo.getBytes();
		for(int i = 0; i < bar.length; i++)
		{
			message.update(bar[i]);
		}
		System.out.println(message.finish());

	}
}
__________________
Lo, there do I see my father. 'Lo, there do I see My mother, and my sisters, and my brothers. 'Lo, there do I see The line of my people... Back to the beginning. 'Lo, they do call to me. They bid me take my place among them. In the halls of Valhalla... Where the brave... May live... ...forever.. GrimBB | Mimesis
grimpirate is offline   Reply With Quote
Old Aug 8th, 2006, 5:57 AM   #9
grimpirate
King of Portal
 
grimpirate's Avatar
 
Join Date: Sep 2005
Posts: 439
Rep Power: 4 grimpirate is on a distinguished road
Send a message via Yahoo to grimpirate
I think I'm going to take Rivest's idea and just make my own algorithm by ignoring the whole little-endian big-endian conversion. It seems like a grandiose waste of processing cycles and of no significant mathematical importance. Onward with pirate recklessness.
__________________
Lo, there do I see my father. 'Lo, there do I see My mother, and my sisters, and my brothers. 'Lo, there do I see The line of my people... Back to the beginning. 'Lo, they do call to me. They bid me take my place among them. In the halls of Valhalla... Where the brave... May live... ...forever.. GrimBB | Mimesis
grimpirate is offline   Reply With Quote
Reply

Bookmarks

« Previous Thread in Forum | Next Thread in Forum »

Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
Could this get me in trouble? (Reg. Internet Copyright Laws) Sane Coder's Corner Lounge 14 Jan 26th, 2006 7:14 PM
implementation of cpuid and graph in my benchmark programm chorijan C++ 0 Sep 7th, 2005 7:27 AM
ftell() giving me trouble. 2roll4life7 C 5 Sep 2nd, 2005 1:27 PM
Having trouble with an exercise in the C book. linuxpimp20 C 6 Jul 6th, 2005 8:22 AM
Can anyone do this? Im having trouble with classes jlessard04 C++ 10 Apr 30th, 2005 8:10 PM




DaniWeb IT Discussion Community
All times are GMT -5. The time now is 10:26 PM.

Powered by vBulletin® Version 3.7.0, Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Copyright ©2007 DaniWeb® LLC