/* * Class for implementing the (notoriously weak) md4 hash algorithm. * * 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(). * * Written for jotp, by Harry Mantakos harry@meretrix.com * * Feel free to do whatever you like with this code. * If you do modify or use this code in another application, * I'd be interested in hearing from you! * * Included in Ganymede * * Created: 15 March 2001 * Version: $Revision$ * Last Mod Date: $Date$ */ package arlut.csd.crypto; /*------------------------------------------------------------------------------ class md4 ------------------------------------------------------------------------------*/ public class Md4 { private int A,B,C,D; private int d[]; private int numwords; /* -- */ /** * For verification of a modicum of sanity, run a few * test strings through */ public static void main(final String argv[]) { /* Test cases, mostly taken from rfc 1320 */ final String str[] = { "" , "a", "abc", "message digest", "abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", "12345678901234567890123456789012345678901234567890123456789012345678901234567890", "01234567890123456789012345678901234567890123456789012345"}; for (int i = 0; i < str.length; i++) { final Md4 mdc = new Md4(str[i]); mdc.calc(); //System.out.println("md4(\"" + str[i] + "\") = " + mdc); } } static int F(final int x, final int y, final int z) { return ((x & y) | (~x & z)); } static int G(final int x, final int y, final int z) { return ((x & y) | (x & z) | (y & z)); } static int H(final int x, final int y, final int z) { return (x ^ y ^ z); } static int rotintlft(final int val, final int numbits) { return ((val << numbits) | (val >>> (32 - numbits))); } static String tohex(int i) { final StringBuilder buf = new StringBuilder(); for (int b = 0; b < 4; b++) { buf.append(Integer.toString((i >> 4) & 0xf, 16)); buf.append(Integer.toString(i & 0xf, 16)); i >>= 8; } return buf.toString().toUpperCase(); } // --- /** * String constructor for md4 */ public Md4(final String s) { final byte in[] = new byte[s.length()]; int i; for (i=0; i < s.length(); i++) { in[i] = (byte) (s.charAt(i) & 0xff); } mdinit(in); } /** * Byte array constructor for md4 */ public Md4(final byte in[]) { mdinit(in); } public int[] getregs() { final int regs[] = {this.A, this.B, this.C, this.D}; return regs; } public 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); A += AA; B+= BB; C+= CC; D+= DD; } } @Override public String toString() { final String s; return (tohex(A) + tohex(B) + tohex(C) + tohex(D)); } private void mdinit(final 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; final 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); } } private void round1(final 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); } private void round2(final 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); } private void round3(final 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); } }