FileDocCategorySizeDatePackage
md.javaAPI DocExample13317Sat Nov 25 11:54:32 GMT 2000None

md.java

/* Class for implementing md4 hash algorithm (and hopefully md5 eventually).
 * There are constructors for prepping the hash algorithm (doing the
 * padding, mainly) for a String or a byte[], and an mdcalc() method 
 * for generating the hash. The results can be accessed as an int array 
 * by getregs(), or as a String of hex digits with toString().
 *
 * Copyright 1996 Harry Mantakos, harry@cs.umd.edu
 */

class md4 extends md {
    md4(String s) {
	super(s);
    }
    md4(byte in[]) {
	super(in);
    }
    static int F(int x, int y, int z) {
	return((x & y) | (~x & z));
    }
    static int G(int x, int y, int z) {
	return((x & y) | (x & z) | (y & z));
    }
    static int H(int x, int y, int z) {
	return(x ^ y ^ z);
    }
    void round1(int blk) {
	A = rotintlft((A + F(B, C, D) + d[0 + 16 * blk]), 3);
	D = rotintlft((D + F(A, B, C) + d[1 + 16 * blk]), 7);
	C = rotintlft((C + F(D, A, B) + d[2 + 16 * blk]), 11);
	B = rotintlft((B + F(C, D, A) + d[3 + 16 * blk]), 19);

	A = rotintlft((A + F(B, C, D) + d[4 + 16 * blk]), 3);
	D = rotintlft((D + F(A, B, C) + d[5 + 16 * blk]), 7);
	C = rotintlft((C + F(D, A, B) + d[6 + 16 * blk]), 11);
	B = rotintlft((B + F(C, D, A) + d[7 + 16 * blk]), 19);

	A = rotintlft((A + F(B, C, D) + d[8 + 16 * blk]), 3);
	D = rotintlft((D + F(A, B, C) + d[9 + 16 * blk]), 7);
	C = rotintlft((C + F(D, A, B) + d[10 + 16 * blk]), 11);
	B = rotintlft((B + F(C, D, A) + d[11 + 16 * blk]), 19);

	A = rotintlft((A + F(B, C, D) + d[12 + 16 * blk]), 3);
	D = rotintlft((D + F(A, B, C) + d[13 + 16 * blk]), 7);
	C = rotintlft((C + F(D, A, B) + d[14 + 16 * blk]), 11);
	B = rotintlft((B + F(C, D, A) + d[15 + 16 * blk]), 19);
    }
    void round2(int blk) {
	A = rotintlft((A + G(B, C, D) + d[0 + 16 * blk] + 0x5a827999), 3);
	D = rotintlft((D + G(A, B, C) + d[4 + 16 * blk] + 0x5a827999), 5);
	C = rotintlft((C + G(D, A, B) + d[8 + 16 * blk] + 0x5a827999), 9);
	B = rotintlft((B + G(C, D, A) + d[12 + 16 * blk] + 0x5a827999), 13);

	A = rotintlft((A + G(B, C, D) + d[1 + 16 * blk] + 0x5a827999), 3);
	D = rotintlft((D + G(A, B, C) + d[5 + 16 * blk] + 0x5a827999), 5);
	C = rotintlft((C + G(D, A, B) + d[9 + 16 * blk] + 0x5a827999), 9);
	B = rotintlft((B + G(C, D, A) + d[13 + 16 * blk] + 0x5a827999), 13);

	A = rotintlft((A + G(B, C, D) + d[2 + 16 * blk] + 0x5a827999), 3);
	D = rotintlft((D + G(A, B, C) + d[6 + 16 * blk] + 0x5a827999), 5);
	C = rotintlft((C + G(D, A, B) + d[10 + 16 * blk] + 0x5a827999), 9);
	B = rotintlft((B + G(C, D, A) + d[14 + 16 * blk] + 0x5a827999), 13);

	A = rotintlft((A + G(B, C, D) + d[3 + 16 * blk] + 0x5a827999), 3);
	D = rotintlft((D + G(A, B, C) + d[7 + 16 * blk] + 0x5a827999), 5);
	C = rotintlft((C + G(D, A, B) + d[11 + 16 * blk] + 0x5a827999), 9);
	B = rotintlft((B + G(C, D, A) + d[15 + 16 * blk] + 0x5a827999), 13);

    }
    void round3(int blk) {
	A = rotintlft((A + H(B, C, D) + d[0 + 16 * blk] + 0x6ed9eba1), 3);
	D = rotintlft((D + H(A, B, C) + d[8 + 16 * blk] + 0x6ed9eba1), 9);
	C = rotintlft((C + H(D, A, B) + d[4 + 16 * blk] + 0x6ed9eba1), 11);
	B = rotintlft((B + H(C, D, A) + d[12 + 16 * blk] + 0x6ed9eba1), 15);

	A = rotintlft((A + H(B, C, D) + d[2 + 16 * blk] + 0x6ed9eba1), 3);
	D = rotintlft((D + H(A, B, C) + d[10 + 16 * blk] + 0x6ed9eba1), 9);
	C = rotintlft((C + H(D, A, B) + d[6 + 16 * blk] + 0x6ed9eba1), 11);
	B = rotintlft((B + H(C, D, A) + d[14 + 16 * blk] + 0x6ed9eba1), 15);

	A = rotintlft((A + H(B, C, D) + d[1 + 16 * blk] + 0x6ed9eba1), 3);
	D = rotintlft((D + H(A, B, C) + d[9 + 16 * blk] + 0x6ed9eba1), 9);
	C = rotintlft((C + H(D, A, B) + d[5 + 16 * blk] + 0x6ed9eba1), 11);
	B = rotintlft((B + H(C, D, A) + d[13 + 16 * blk] + 0x6ed9eba1), 15);

	A = rotintlft((A + H(B, C, D) + d[3 + 16 * blk] + 0x6ed9eba1), 3);
	D = rotintlft((D + H(A, B, C) + d[11 + 16 * blk] + 0x6ed9eba1), 9);
	C = rotintlft((C + H(D, A, B) + d[7 + 16 * blk] + 0x6ed9eba1), 11);
	B = rotintlft((B + H(C, D, A) + d[15 + 16 * blk] + 0x6ed9eba1), 15);

    }
    void round4(int blk) {
	System.out.println(" must be md5, in round4!");
    }
}

class md5 extends md {
    md5(String s) {
	super(s);
    }
    md5(byte in[]) {
	super(in);
    }
    static int F(int x, int y, int z) {
	return((x & y) | (~x & z));
    }
    static int G(int x, int y, int z) {
	return((x & z) | (y & ~z));
    }
    static int H(int x, int y, int z) {
	return(x ^ y ^ z);
    }
    static int I(int x, int y, int z) {
	return(y ^ (x | ~z));
    }
    void round1(int blk) {
	A = rotintlft(A + F(B, C, D) + d[0 + 16 * blk] +
		      0xd76aa478, 7) + B;
	D = rotintlft(D + F(A, B, C) + d[1 + 16 * blk] +
		      0xe8c7b756, 12) + A;
	C = rotintlft(C + F(D, A, B) + d[2 + 16 * blk] +
		      0x242070db, 17) + D;
	B = rotintlft(B + F(C, D, A) + d[3 + 16 * blk] +
		      0xc1bdceee, 22) + C;

	A = rotintlft(A + F(B, C, D) + d[4 + 16 * blk] +
		      0xf57c0faf, 7) + B;
	D = rotintlft(D + F(A, B, C) + d[5 + 16 * blk] +
		      0x4787c62a, 12) + A;
	C = rotintlft(C + F(D, A, B) + d[6 + 16 * blk] +
		      0xa8304613, 17) + D;
	B = rotintlft(B + F(C, D, A) + d[7 + 16 * blk] +
		      0xfd469501, 22) + C;
	A = rotintlft(A + F(B, C, D) + d[8 + 16 * blk] +
		      0x698098d8, 7) + B;
	D = rotintlft(D + F(A, B, C) + d[9 + 16 * blk] +
		      0x8b44f7af, 12) + A;
	C = rotintlft(C + F(D, A, B) + d[10 + 16 * blk] +
		      0xffff5bb1, 17) + D;
	B = rotintlft(B + F(C, D, A) + d[11 + 16 * blk] +
		      0x895cd7be, 22) + C;
	A = rotintlft(A + F(B, C, D) + d[12 + 16 * blk] +
		      0x6b901122, 7) + B;
	D = rotintlft(D + F(A, B, C) + d[13 + 16 * blk] +
		      0xfd987193, 12) + A;
	C = rotintlft(C + F(D, A, B) + d[14 + 16 * blk] +
		      0xa679438e, 17) + D;
	B = rotintlft(B + F(C, D, A) + d[15 + 16 * blk] +
		      0x49b40821, 22) + C;
    }
    void round2(int blk) {
	A = rotintlft(A + G(B, C, D) + d[1 + 16 * blk] +
		      0xf61e2562, 5) + B;
	D = rotintlft(D + G(A, B, C) + d[6 + 16 * blk] +
		      0xc040b340, 9) + A;
	C = rotintlft(C + G(D, A, B) + d[11 + 16 * blk] +
		      0x265e5a51, 14) + D;
	B = rotintlft(B + G(C, D, A) + d[0 + 16 * blk] +
		      0xe9b6c7aa, 20) + C;
	A = rotintlft(A + G(B, C, D) + d[5 + 16 * blk] +
		      0xd62f105d, 5) + B;
	D = rotintlft(D + G(A, B, C) + d[10 + 16 * blk] +
		      0x02441453, 9) + A;
	C = rotintlft(C + G(D, A, B) + d[15 + 16 * blk] + 
		      0xd8a1e681, 14) + D;
	B = rotintlft(B + G(C, D, A) + d[4 + 16 * blk] +
		      0xe7d3fbc8, 20) + C;
	A = rotintlft(A + G(B, C, D) + d[9 + 16 * blk] +
		      0x21e1cde6, 5) + B;
	D = rotintlft(D + G(A, B, C) + d[14 + 16 * blk] +
		      0xc33707d6, 9) + A;
	C = rotintlft(C + G(D, A, B) + d[3 + 16 * blk] +
		      0xf4d50d87, 14) + D;
	B = rotintlft(B + G(C, D, A) + d[8 + 16 * blk] +
		      0x455a14ed, 20) + C;
	A = rotintlft(A + G(B, C, D) + d[13 + 16 * blk] +
		      0xa9e3e905, 5) + B;
	D = rotintlft(D + G(A, B, C) + d[2 + 16 * blk] +
		      0xfcefa3f8, 9) + A;
	C = rotintlft(C + G(D, A, B) + d[7 + 16 * blk] +
		      0x676f02d9, 14) + D;
	B = rotintlft(B + G(C, D, A) + d[12 + 16 * blk] +
		      0x8d2a4c8a, 20) + C;
    }
    void round3(int blk) {
	A = rotintlft(A + H(B, C, D) + d[5 + 16 * blk] +
		      0xfffa3942, 4) + B;
	D = rotintlft(D + H(A, B, C) + d[8 + 16 * blk] +
		      0x8771f681, 11) + A;
	C = rotintlft(C + H(D, A, B) + d[11 + 16 * blk] +
		      0x6d9d6122, 16) + D;
	B = rotintlft(B + H(C, D, A) + d[14 + 16 * blk] +
		      0xfde5380c, 23) + C;
	A = rotintlft(A + H(B, C, D) + d[1 + 16 * blk] +
		      0xa4beea44, 4) + B;
	D = rotintlft(D + H(A, B, C) + d[4 + 16 * blk] +
		      0x4bdecfa9, 11) + A;
	C = rotintlft(C + H(D, A, B) + d[7 + 16 * blk] +
		      0xf6bb4b60, 16) + D;
	B = rotintlft(B + H(C, D, A) + d[10 + 16 * blk] +
		      0xbebfbc70, 23) + C;
	A = rotintlft(A + H(B, C, D) + d[13 + 16 * blk] +
		      0x289b7ec6, 4) + B;
	D = rotintlft(D + H(A, B, C) + d[0 + 16 * blk] +
		      0xeaa127fa, 11) + A;
	C = rotintlft(C + H(D, A, B) + d[3 + 16 * blk] +
		      0xd4ef3085, 16) + D;
	B = rotintlft(B + H(C, D, A) + d[6 + 16 * blk] +
		      0x04881d05, 23) + C;
	A = rotintlft(A + H(B, C, D) + d[9 + 16 * blk] +
		      0xd9d4d039, 4) + B;
	D = rotintlft(D + H(A, B, C) + d[12 + 16 * blk] +
		      0xe6db99e5, 11) + A;
	C = rotintlft(C + H(D, A, B) + d[15 + 16 * blk] +
		      0x1fa27cf8, 16) + D;
	B = rotintlft(B + H(C, D, A) + d[2 + 16 * blk] +
		      0xc4ac5665, 23) + C;
    }
    void round4(int blk) {
	A = rotintlft(A + I(B, C, D) + d[0 + 16 * blk] +
		      0xf4292244, 6) + B;
	D = rotintlft(D + I(A, B, C) + d[7 + 16 * blk] +
		      0x432aff97, 10) + A;
	C = rotintlft(C + I(D, A, B) + d[14 + 16 * blk] +
		      0xab9423a7, 15) + D;
	B = rotintlft(B + I(C, D, A) + d[5 + 16 * blk] +
		      0xfc93a039, 21) + C;
	A = rotintlft(A + I(B, C, D) + d[12 + 16 * blk] +
		      0x655b59c3, 6) + B;
	D = rotintlft(D + I(A, B, C) + d[3 + 16 * blk] +
		      0x8f0ccc92, 10) + A;
	C = rotintlft(C + I(D, A, B) + d[10 + 16 * blk] +
		      0xffeff47d, 15) + D;
	B = rotintlft(B + I(C, D, A) + d[1 + 16 * blk] +
		      0x85845dd1, 21) + C;
	A = rotintlft(A + I(B, C, D) + d[8 + 16 * blk] +
		      0x6fa87e4f, 6) + B;
	D = rotintlft(D + I(A, B, C) + d[15 + 16 * blk] +
		      0xfe2ce6e0, 10) + A;
	C = rotintlft(C + I(D, A, B) + d[6 + 16 * blk] +
		      0xa3014314, 15) + D;
	B = rotintlft(B + I(C, D, A) + d[13 + 16 * blk] +
		      0x4e0811a1, 21) + C;
	A = rotintlft(A + I(B, C, D) + d[4 + 16 * blk] +
		      0xf7537e82, 6) + B;
	D = rotintlft(D + I(A, B, C) + d[11 + 16 * blk] +
		      0xbd3af235, 10) + A;
	C = rotintlft(C + I(D, A, B) + d[2 + 16 * blk] +
		      0x2ad7d2bb, 15) + D;
	B = rotintlft(B + I(C, D, A) + d[9 + 16 * blk] +
		      0xeb86d391, 21) + C;
    }
}

class md {
    int A,B,C,D;
    int d[];
    int numwords;

    /* For verification of a modicum of sanity, run a few 
     * test strings through
     */
    public static void main(String[] argv) {
	boolean doinmd4;
	String mdtype;
	/* Test cases, mostly taken from rfc 1320 */
	String str[] = { "" , "a", "abc", "message digest", 
			 "abcdefghijklmnopqrstuvwxyz", 
	   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 
 "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
	 "01234567890123456789012345678901234567890123456789012345"};

	if (argv.length == 0) {
	    mdtype = "md4";
	    doinmd4 = true;
	} else if (argv.length > 1) {
	    System.err.println("Usage: md [4|5|md4|md5]");
	    return;
	} else	if ((argv[0].equals("4")) || (argv[0].equals("md4"))) {
	    mdtype = "md4";
	    doinmd4 = true;
	} else if ((argv[0].equals("5")) || (argv[0].equals("md5"))) {
	    mdtype = "md5";
	    doinmd4 = false;
	} else {
	    System.err.println("Usage: md [4|5|md4|md5]");
	    return;
	}
	for(int i = 0; i < str.length; i++) {
	    if (doinmd4) {
		md4 mdc = new md4(str[i]);
		mdc.calc();
		System.out.println(mdtype + "(\"" + str[i] + "\") = " + mdc);
	    } else {
		md5 mdc = new md5(str[i]);
		mdc.calc();
		System.out.println(mdtype + "(\"" + str[i] + "\") = " + mdc);
	    }
	}
    }
    md (String s) {
	byte in[] = new byte[s.length()];
	int i;

	for(i=0; i < s.length(); i++) {
	    in[i] = (byte) (s.charAt(i) & 0xff);
	}
	mdinit(in);
    }
    md (byte in[]) {
	mdinit(in);
    }

    void mdinit (byte in[]) {
	int newlen, endblklen, pad, i;
	long datalenbits;

	datalenbits = in.length  * 8;
	endblklen = in.length % 64;
	if (endblklen < 56) {
	    pad = 64 - endblklen;
	} else {
	    pad = (64 - endblklen) + 64;
	}
	newlen = in.length + pad;
	byte b[] = new byte[newlen];
	for(i=0; i < in.length; i++) {
	    b[i] = in[i];
	}
	b[in.length] = (byte) 0x80;
	for (i = b.length + 1; i < (newlen - 8); i++) {
	    b[i] = 0;
	}
	for (i = 0; i < 8; i++) {
	    b[newlen - 8 + i] = (byte) (datalenbits & 0xff);
	    datalenbits >>= 8;
	}
	/* init registers */
	A = 0x67452301;
	B = 0xefcdab89;
	C = 0x98badcfe;
	D = 0x10325476;
	this.numwords = newlen/4;
	this.d = new int[this.numwords];
	for (i = 0; i < newlen; i += 4) {
	    this.d[i/4] = (b[i] & 0xff) + ((b[i+1] & 0xff) << 8) + 
		((b[i+2] & 0xff) << 16) + ((b[i+3] & 0xff) << 24);
	}
   }
	
    public String toString() {
	String s;

	return(tohex(A) + tohex(B) + tohex(C) + tohex(D));
    }
    int[] getregs() {
	int regs[] = {this.A, this.B, this.C, this.D};

	return regs;
    }
    void calc() {
	int AA, BB, CC, DD, i;

	for(i=0; i < numwords/16; i++) {
	    AA = A; BB = B; CC = C; DD = D;
	    round1(i);
	    round2(i);
	    round3(i);
            if (this instanceof md5) {
		round4(i);
	    }
	    A += AA; B+= BB; C+= CC; D+= DD;
	}
    }
    /* Dummy round*() methods. these are overriden in the md4 and md5 
     * subclasses 
     */
    void round1(int blk) {
	System.err.println("Danger! Danger! Someone called md.round1()!");
    }
    void round2(int blk) {
	System.err.println("Danger! Danger! Someone called md.round2()!");
    }
    void round3(int blk) {
	System.err.println("Danger! Danger! Someone called md.round3()!");
    }
    void round4(int blk) {
	System.err.println("Danger! Danger! Someone called md.round4()!");
    }
    static int rotintlft(int val, int numbits) {
	return((val << numbits) | (val >>> (32 - numbits)));
    }
    static String tohex(int i) {
	int b;
	String tmpstr;

	tmpstr = "";
	for(b = 0; b < 4; b++) {
	    tmpstr += Integer.toString((i >> 4) & 0xf, 16) 
		+ Integer.toString(i & 0xf, 16);
	    i >>= 8;
	}
	return tmpstr;
    }

}