FileDocCategorySizeDatePackage
MD5.javaAPI DocAzureus 3.0.3.411572Thu Feb 09 19:42:44 GMT 2006org.gudy.azureus2.core3.util

MD5

public class MD5 extends Object
author
Olivier Chalouhi

Fields Summary
private int
h0
private int
h1
private int
h2
private int
h3
private int
length
private ByteBuffer
finalBuffer
Constructors Summary
public MD5()

    finalBuffer = ByteBuffer.allocate(64);
    finalBuffer.position(0);
    finalBuffer.limit(64);
    
    reset();
  
Methods Summary
private voidcompleteFinalBuffer(java.nio.ByteBuffer buffer)

    if(finalBuffer.position() == 0) 
      return;
    
    while(buffer.remaining() > 0 && finalBuffer.remaining() > 0) {
      finalBuffer.put(buffer.get());
    }
    
    if(finalBuffer.remaining() == 0) {
      finalBuffer.position(0);
      transform(finalBuffer);
      finalBuffer.position(0);
    }
  
public byte[]digest()
Finishes the MD5-1 message digest calculation.

return
16-byte hash result

    byte[] result = new byte[16];
    
    finalBuffer.put((byte)0x80);
    if(finalBuffer.remaining() < 8) {
      while(finalBuffer.remaining() > 0) {
        finalBuffer.put((byte)0);
      }
      finalBuffer.position(0);
      transform(finalBuffer);
      finalBuffer.position(0);
    }
    
    while(finalBuffer.remaining() > 8) {
      finalBuffer.put((byte)0);
    }
    
    finalBuffer.putLong(length << 3);
    finalBuffer.position(0);
    transform(finalBuffer);
    
    finalBuffer.position(0);
    finalBuffer.putInt(h3);
    finalBuffer.putInt(h2);
    finalBuffer.putInt(h1);
    finalBuffer.putInt(h0);    
    finalBuffer.position(0);
    
    for(int i  = 0 ; i < 16 ; i++) {
     result[15-i] = finalBuffer.get(); 
    }
    
    return result;
  
public byte[]digest(java.nio.ByteBuffer buffer)
Finishes the MD5 message digest calculation, by first performing a final update from the given input buffer, then completing the calculation as with digest().

param
buffer input data
return
16-byte hash result

    update( buffer );
    return digest();
  
public static voidmain(java.lang.String[] args)

    MD5 md5Gudy = new MD5();
    BrokenMd5Hasher md5Jmule = new BrokenMd5Hasher();
    MessageDigest md5Sun = MessageDigest.getInstance("MD5");
    
    ByteBuffer bhashJ = ByteBuffer.allocate(16);
    
    
    System.out.println("Gudy : " + ByteFormatter.nicePrint(md5Gudy.digest()));
    md5Gudy.reset();
    md5Jmule.finalDigest(bhashJ);
    bhashJ.rewind();      
    byte hashJ[] = bhashJ.array();
    System.out.println("Jmule: " + ByteFormatter.nicePrint(hashJ));
    System.out.println("Sun: " + ByteFormatter.nicePrint(md5Sun.digest()));
    
    for(int i = 0 ; i < 1 ; i++) {
      ByteBuffer test = ByteBuffer.allocate(i);
      while(test.remaining() > 0) {
        test.put((byte)(Math.random() * 256));
      }
      test.rewind();
      byte hashG[] = md5Gudy.digest(test);
      md5Gudy.reset();
      
      md5Jmule.update(test);      
      bhashJ.rewind();
      md5Jmule.finalDigest(bhashJ);
      bhashJ.rewind();      
      hashJ = bhashJ.array();
      test.rewind();
      
      md5Sun.update(test.array());
      byte hashS[] = md5Sun.digest();
      
      System.out.println("Gudy : " + ByteFormatter.nicePrint(hashG));
      System.out.println("Jmule: " + ByteFormatter.nicePrint(hashJ));
      System.out.println("Sun: " + ByteFormatter.nicePrint(hashS));
      //boolean same = true;

      //System.out.println(i + " : " + same);      
    }
  
public voidreset()
Resets the MD5 to initial state for a new message digest calculation. Must be called before starting a new hash calculation.

    h0 = 0x67452301;
    h1 = 0xEFCDAB89;
    h2 = 0x98BADCFE;
    h3 = 0x10325476;   
    
    length = 0;
    
    finalBuffer.clear();
  
public voidtransform(java.nio.ByteBuffer M)

    
    int x0 , x1 , x2 , x3 ,  x4 , x5 , x6 , x7 , x8 , x9 ,
    x10, x11, x12, x13, x14, x15;
    
    int a,b,c,d;
    
    /*
     * Crazy byte order for MD5 ... took me hours to find out
     * where the problem was .... words (32 bits) must be read starting
     * with the least significant byte !
     */
    ByteOrder order = M.order();
    M.order(ByteOrder.LITTLE_ENDIAN);
    
    x0 = M.getInt();
    x1 = M.getInt();
    x2 = M.getInt();
    x3 = M.getInt();
    x4 = M.getInt();
    x5 = M.getInt();
    x6 = M.getInt();
    x7 = M.getInt();
    x8 = M.getInt();
    x9 = M.getInt();
    x10 = M.getInt();
    x11 = M.getInt();
    x12 = M.getInt();
    x13 = M.getInt();
    x14 = M.getInt();
    x15 = M.getInt();
    
    M.order(order);
    
    a = h0 ; b = h1 ; c = h2 ; d = h3 ;
    
    
    a += ((b & c) | ( ~b & d)) + x0 + 0xd76aa478;
    a = b + ((a << 7) | (a >>> 25));
    d += ((a & b) | ( ~a & c)) + x1 + 0xe8c7b756;
    d = a + ((d << 12) | (d >>> 20));
    c += ((d & a) | ( ~d & b)) + x2 + 0x242070db;
    c = d + ((c << 17) | (c >>> 15));
    b += ((c & d) | ( ~c & a)) + x3 + 0xc1bdceee;
    b = c + ((b << 22) | (b >>> 10));
    a += ((b & c) | ( ~b & d)) + x4 + 0xf57c0faf;
    a = b + ((a << 7) | (a >>> 25));
    d += ((a & b) | ( ~a & c)) + x5 + 0x4787c62a;
    d = a + ((d << 12) | (d >>> 20));
    c += ((d & a) | ( ~d & b)) + x6 + 0xa8304613;
    c = d + ((c << 17) | (c >>> 15));
    b += ((c & d) | ( ~c & a)) + x7 + 0xfd469501;
    b = c + ((b << 22) | (b >>> 10));
    a += ((b & c) | ( ~b & d)) + x8 + 0x698098d8;
    a = b + ((a << 7) | (a >>> 25));
    d += ((a & b) | ( ~a & c)) + x9 + 0x8b44f7af;
    d = a + ((d << 12) | (d >>> 20));
    c += ((d & a) | ( ~d & b)) + x10 + 0xffff5bb1;
    c = d + ((c << 17) | (c >>> 15));
    b += ((c & d) | ( ~c & a)) + x11 + 0x895cd7be;
    b = c + ((b << 22) | (b >>> 10));
    a += ((b & c) | ( ~b & d)) + x12 + 0x6b901122;
    a = b + ((a << 7) | (a >>> 25));
    d += ((a & b) | ( ~a & c)) + x13 + 0xfd987193;
    d = a + ((d << 12) | (d >>> 20));
    c += ((d & a) | ( ~d & b)) + x14 + 0xa679438e;
    c = d + ((c << 17) | (c >>> 15));
    b += ((c & d) | ( ~c & a)) + x15 + 0x49b40821;
    b = c + ((b << 22) | (b >>> 10));
    
    a += ((b & d) | (c & ~d)) + x1 + 0xf61e2562;
    a = b + ((a << 5) | (a >>> 27));
    d += ((a & c) | (b & ~c)) + x6 + 0xc040b340;
    d = a + ((d << 9) | (d >>> 23));
    c += ((d & b) | (a & ~b)) + x11 + 0x265e5a51;
    c = d + ((c << 14) | (c >>> 18));
    b += ((c & a) | (d & ~a)) + x0 + 0xe9b6c7aa;
    b = c + ((b << 20) | (b >>> 12));
    a += ((b & d) | (c & ~d)) + x5 + 0xd62f105d;
    a = b + ((a << 5) | (a >>> 27));
    d += ((a & c) | (b & ~c)) + x10 + 0x2441453;
    d = a + ((d << 9) | (d >>> 23));
    c += ((d & b) | (a & ~b)) + x15 + 0xd8a1e681;
    c = d + ((c << 14) | (c >>> 18));
    b += ((c & a) | (d & ~a)) + x4 + 0xe7d3fbc8;
    b = c + ((b << 20) | (b >>> 12));
    a += ((b & d) | (c & ~d)) + x9 + 0x21e1cde6;
    a = b + ((a << 5) | (a >>> 27));
    d += ((a & c) | (b & ~c)) + x14 + 0xc33707d6;
    d = a + ((d << 9) | (d >>> 23));
    c += ((d & b) | (a & ~b)) + x3 + 0xf4d50d87;
    c = d + ((c << 14) | (c >>> 18));
    b += ((c & a) | (d & ~a)) + x8 + 0x455a14ed;
    b = c + ((b << 20) | (b >>> 12));
    a += ((b & d) | (c & ~d)) + x13 + 0xa9e3e905;
    a = b + ((a << 5) | (a >>> 27));
    d += ((a & c) | (b & ~c)) + x2 + 0xfcefa3f8;
    d = a + ((d << 9) | (d >>> 23));
    c += ((d & b) | (a & ~b)) + x7 + 0x676f02d9;
    c = d + ((c << 14) | (c >>> 18));
    b += ((c & a) | (d & ~a)) + x12 + 0x8d2a4c8a;
    b = c + ((b << 20) | (b >>> 12));
    a += (b ^ c ^ d) + x5 + 0xfffa3942;
    a = b + ((a << 4) | (a >>> 28));
    d += (a ^ b ^ c) + x8 + 0x8771f681;
    d = a + ((d << 11) | (d >>> 21));
    c += (d ^ a ^ b) + x11 + 0x6d9d6122;
    c = d + ((c << 16) | (c >>> 16));
    b += (c ^ d ^ a) + x14 + 0xfde5380c;
    b = c + ((b << 23) | (b >>> 9));
    a += (b ^ c ^ d) + x1 + 0xa4beea44;
    a = b + ((a << 4) | (a >>> 28));
    d += (a ^ b ^ c) + x4 + 0x4bdecfa9;
    d = a + ((d << 11) | (d >>> 21));
    c += (d ^ a ^ b) + x7 + 0xf6bb4b60;
    c = d + ((c << 16) | (c >>> 16));
    b += (c ^ d ^ a) + x10 + 0xbebfbc70;
    b = c + ((b << 23) | (b >>> 9));
    a += (b ^ c ^ d) + x13 + 0x289b7ec6;
    a = b + ((a << 4) | (a >>> 28));
    d += (a ^ b ^ c) + x0 + 0xeaa127fa;
    d = a + ((d << 11) | (d >>> 21));
    c += (d ^ a ^ b) + x3 + 0xd4ef3085;
    c = d + ((c << 16) | (c >>> 16));
    b += (c ^ d ^ a) + x6 + 0x4881d05;
    b = c + ((b << 23) | (b >>> 9));
    a += (b ^ c ^ d) + x9 + 0xd9d4d039;
    a = b + ((a << 4) | (a >>> 28));
    d += (a ^ b ^ c) + x12 + 0xe6db99e5;
    d = a + ((d << 11) | (d >>> 21));
    c += (d ^ a ^ b) + x15 + 0x1fa27cf8;
    c = d + ((c << 16) | (c >>> 16));
    b += (c ^ d ^ a) + x2 + 0xc4ac5665;
    b = c + ((b << 23) | (b >>> 9));
    a += (c ^ (b  | ~d)) + x0 + 0xf4292244;
    a = b + ((a << 6) | (a >>> 26));
    d += (b ^ (a  | ~c)) + x7 + 0x432aff97;
    d = a + ((d << 10) | (d >>> 22));
    c += (a ^ (d  | ~b)) + x14 + 0xab9423a7;
    c = d + ((c << 15) | (c >>> 17));
    b += (d ^ (c  | ~a)) + x5 + 0xfc93a039;
    b = c + ((b << 21) | (b >>> 11));
    a += (c ^ (b  | ~d)) + x12 + 0x655b59c3;
    a = b + ((a << 6) | (a >>> 26));
    d += (b ^ (a  | ~c)) + x3 + 0x8f0ccc92;
    d = a + ((d << 10) | (d >>> 22));
    c += (a ^ (d  | ~b)) + x10 + 0xffeff47d;
    c = d + ((c << 15) | (c >>> 17));
    b += (d ^ (c  | ~a)) + x1 + 0x85845dd1;
    b = c + ((b << 21) | (b >>> 11));
    a += (c ^ (b  | ~d)) + x8 + 0x6fa87e4f;
    a = b + ((a << 6) | (a >>> 26));
    d += (b ^ (a  | ~c)) + x15 + 0xfe2ce6e0;
    d = a + ((d << 10) | (d >>> 22));
    c += (a ^ (d  | ~b)) + x6 + 0xa3014314;
    c = d + ((c << 15) | (c >>> 17));
    b += (d ^ (c  | ~a)) + x13 + 0x4e0811a1;
    b = c + ((b << 21) | (b >>> 11));
    a += (c ^ (b  | ~d)) + x4 + 0xf7537e82;
    a = b + ((a << 6) | (a >>> 26));
    d += (b ^ (a  | ~c)) + x11 + 0xbd3af235;
    d = a + ((d << 10) | (d >>> 22));
    c += (a ^ (d  | ~b)) + x2 + 0x2ad7d2bb;
    c = d + ((c << 15) | (c >>> 17));
    b += (d ^ (c  | ~a)) + x9 + 0xeb86d391;
    b = c + ((b << 21) | (b >>> 11));

    
    h0 += a;
    h1 += b;
    h2 += c;
    h3 += d;    
  
public voidupdate(java.nio.ByteBuffer buffer)
Starts or continues a MD5 message digest calculation. Only the remaining bytes of the given ByteBuffer are used.

param
buffer input data

    length += buffer.remaining();
    //Save current position to leave given buffer unchanged
    int position = buffer.position();
    
    //Complete the final buffer if needed
    completeFinalBuffer(buffer);
    
    while(buffer.remaining() >= 64) {
      transform(buffer);
    }
    
    if(buffer.remaining() != 0) {
      finalBuffer.put(buffer);
    }
    
    buffer.position(position);