| grimpirate |
Aug 2nd, 2006 5:01 PM |
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
|