115 lines
3.1 KiB
Java
115 lines
3.1 KiB
Java
import java.nio.ByteBuffer;
|
|
import java.nio.ByteOrder;
|
|
|
|
class MD5
|
|
{
|
|
|
|
private static final int INIT_A = 0x67452301;
|
|
private static final int INIT_B = (int)0xEFCDAB89L;
|
|
private static final int INIT_C = (int)0x98BADCFEL;
|
|
private static final int INIT_D = 0x10325476;
|
|
|
|
private static final int[] SHIFT_AMTS = {
|
|
7, 12, 17, 22,
|
|
5, 9, 14, 20,
|
|
4, 11, 16, 23,
|
|
6, 10, 15, 21
|
|
};
|
|
|
|
private static final int[] TABLE_T = new int[64];
|
|
static
|
|
{
|
|
for (int i = 0; i < 64; i++)
|
|
TABLE_T[i] = (int)(long)((1L << 32) * Math.abs(Math.sin(i + 1)));
|
|
}
|
|
|
|
public static byte[] computeMD5(byte[] message)
|
|
{
|
|
ByteBuffer padded = ByteBuffer.allocate((((message.length + 8) / 64) + 1) * 64).order(ByteOrder.LITTLE_ENDIAN);
|
|
padded.put(message);
|
|
padded.put((byte)0x80);
|
|
long messageLenBits = (long)message.length * 8;
|
|
padded.putLong(padded.capacity() - 8, messageLenBits);
|
|
|
|
padded.rewind();
|
|
|
|
int a = INIT_A;
|
|
int b = INIT_B;
|
|
int c = INIT_C;
|
|
int d = INIT_D;
|
|
while (padded.hasRemaining()) {
|
|
// obtain a slice of the buffer from the current position,
|
|
// and view it as an array of 32-bit ints
|
|
IntBuffer chunk = padded.slice().order(ByteOrder.LITTLE_ENDIAN).asIntBuffer();
|
|
int originalA = a;
|
|
int originalB = b;
|
|
int originalC = c;
|
|
int originalD = d;
|
|
for (int j = 0; j < 64; j++)
|
|
{
|
|
int div16 = j >>> 4;
|
|
int f = 0;
|
|
int bufferIndex = j;
|
|
switch (div16)
|
|
{
|
|
case 0:
|
|
f = (b & c) | (~b & d);
|
|
break;
|
|
|
|
case 1:
|
|
f = (b & d) | (c & ~d);
|
|
bufferIndex = (bufferIndex * 5 + 1) & 0x0F;
|
|
break;
|
|
|
|
case 2:
|
|
f = b ^ c ^ d;
|
|
bufferIndex = (bufferIndex * 3 + 5) & 0x0F;
|
|
break;
|
|
|
|
case 3:
|
|
f = c ^ (b | ~d);
|
|
bufferIndex = (bufferIndex * 7) & 0x0F;
|
|
break;
|
|
}
|
|
int temp = b + Integer.rotateLeft(a + f + chunk.get(bufferIndex) + TABLE_T[j], SHIFT_AMTS[(div16 << 2) | (j & 3)]);
|
|
a = d;
|
|
d = c;
|
|
c = b;
|
|
b = temp;
|
|
}
|
|
|
|
a += originalA;
|
|
b += originalB;
|
|
c += originalC;
|
|
d += originalD;
|
|
padded.position(padded.position() + 64);
|
|
}
|
|
|
|
ByteBuffer md5 = ByteBuffer.allocate(16).order(ByteOrder.LITTLE_ENDIAN);
|
|
for (int n : new int[]{a, b, c, d})
|
|
{
|
|
md5.putInt(n);
|
|
}
|
|
return md5.array();
|
|
}
|
|
|
|
public static String toHexString(byte[] b)
|
|
{
|
|
StringBuilder sb = new StringBuilder();
|
|
for (int i = 0; i < b.length; i++)
|
|
{
|
|
sb.append(String.format("%02X", b[i] & 0xFF));
|
|
}
|
|
return sb.toString();
|
|
}
|
|
|
|
public static void main(String[] args)
|
|
{
|
|
String[] testStrings = { "", "a", "abc", "message digest", "abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "12345678901234567890123456789012345678901234567890123456789012345678901234567890" };
|
|
for (String s : testStrings)
|
|
System.out.println("0x" + toHexString(computeMD5(s.getBytes())) + " <== \"" + s + "\"");
|
|
return;
|
|
}
|
|
|
|
}
|