001: // This file is currently unlocked (change this line if you lock the file)
002: //
003: // $Log: MD4.java,v $
004: // Revision 1.1.1.1 2005/06/23 15:16:09 smontoro
005: // hipergate backend
006: //
007: // Revision 1.2 1998/01/05 03:41:19 iang
008: // Added references only.
009: //
010: // Revision 1.1.1.1 1997/11/03 22:36:56 hopwood
011: // + Imported to CVS (tagged as 'start').
012: //
013: // Revision 0.1.0.0 1997/07/14 R. Naffah
014: // + original version
015: //
016: // $Endlog$
017: /*
018: * Copyright (c) 1997 Systemics Ltd
019: * on behalf of the Cryptix Development Team. All rights reserved.
020: */
021:
022: package com.knowgate.jcifs.util;
023:
024: import java.security.MessageDigest;
025:
026: /**
027: * Implements the MD4 message digest algorithm in Java.
028: * <p>
029: * <b>References:</b>
030: * <ol>
031: * <li> Ronald L. Rivest,
032: * "<a href="http://www.roxen.com/rfc/rfc1320.html">
033: * The MD4 Message-Digest Algorithm</a>",
034: * IETF RFC-1320 (informational).
035: * </ol>
036: *
037: * <p><b>$Revision: 1.1.1.1 $</b>
038: * @author Raif S. Naffah
039: */
040: public class MD4 extends MessageDigest implements Cloneable {
041: // MD4 specific object variables
042: //...........................................................................
043:
044: /**
045: * The size in bytes of the input block to the tranformation algorithm.
046: */
047: private static final int BLOCK_LENGTH = 64; // = 512 / 8;
048:
049: /**
050: * 4 32-bit words (interim result)
051: */
052: private int[] context = new int[4];
053:
054: /**
055: * Number of bytes processed so far mod. 2 power of 64.
056: */
057: private long count;
058:
059: /**
060: * 512 bits input buffer = 16 x 32-bit words holds until reaches 512 bits.
061: */
062: private byte[] buffer = new byte[BLOCK_LENGTH];
063:
064: /**
065: * 512 bits work buffer = 16 x 32-bit words
066: */
067: private int[] X = new int[16];
068:
069: // Constructors
070: //...........................................................................
071:
072: public MD4() {
073: super ("MD4");
074: engineReset();
075: }
076:
077: /**
078: * This constructor is here to implement cloneability of this class.
079: */
080: private MD4(MD4 md) {
081: this ();
082: context = (int[]) md.context.clone();
083: buffer = (byte[]) md.buffer.clone();
084: count = md.count;
085: }
086:
087: // Cloneable method implementation
088: //...........................................................................
089:
090: /**
091: * Returns a copy of this MD object.
092: */
093: public Object clone() {
094: return new MD4(this );
095: }
096:
097: // JCE methods
098: //...........................................................................
099:
100: /**
101: * Resets this object disregarding any temporary data present at the
102: * time of the invocation of this call.
103: */
104: public void engineReset() {
105: // initial values of MD4 i.e. A, B, C, D
106: // as per rfc-1320; they are low-order byte first
107: context[0] = 0x67452301;
108: context[1] = 0xEFCDAB89;
109: context[2] = 0x98BADCFE;
110: context[3] = 0x10325476;
111: count = 0L;
112: for (int i = 0; i < BLOCK_LENGTH; i++)
113: buffer[i] = 0;
114: }
115:
116: /**
117: * Continues an MD4 message digest using the input byte.
118: */
119: public void engineUpdate(byte b) {
120: // compute number of bytes still unhashed; ie. present in buffer
121: int i = (int) (count % BLOCK_LENGTH);
122: count++; // update number of bytes
123: buffer[i] = b;
124: if (i == BLOCK_LENGTH - 1)
125: transform(buffer, 0);
126: }
127:
128: /**
129: * MD4 block update operation.
130: * <p>
131: * Continues an MD4 message digest operation, by filling the buffer,
132: * transform(ing) data in 512-bit message block(s), updating the variables
133: * context and count, and leaving (buffering) the remaining bytes in buffer
134: * for the next update or finish.
135: *
136: * @param input input block
137: * @param offset start of meaningful bytes in input
138: * @param len count of bytes in input block to consider
139: */
140: public void engineUpdate(byte[] input, int offset, int len) {
141: // make sure we don't exceed input's allocated size/length
142: if (offset < 0 || len < 0 || (long) offset + len > input.length)
143: throw new ArrayIndexOutOfBoundsException();
144:
145: // compute number of bytes still unhashed; ie. present in buffer
146: int bufferNdx = (int) (count % BLOCK_LENGTH);
147: count += len; // update number of bytes
148: int partLen = BLOCK_LENGTH - bufferNdx;
149: int i = 0;
150: if (len >= partLen) {
151: System.arraycopy(input, offset, buffer, bufferNdx, partLen);
152:
153: transform(buffer, 0);
154:
155: for (i = partLen; i + BLOCK_LENGTH - 1 < len; i += BLOCK_LENGTH)
156: transform(input, offset + i);
157: bufferNdx = 0;
158: }
159: // buffer remaining input
160: if (i < len)
161: System.arraycopy(input, offset + i, buffer, bufferNdx, len
162: - i);
163: }
164:
165: /**
166: * Completes the hash computation by performing final operations such
167: * as padding. At the return of this engineDigest, the MD engine is
168: * reset.
169: *
170: * @return the array of bytes for the resulting hash value.
171: */
172: public byte[] engineDigest() {
173: // pad output to 56 mod 64; as RFC1320 puts it: congruent to 448 mod 512
174: int bufferNdx = (int) (count % BLOCK_LENGTH);
175: int padLen = (bufferNdx < 56) ? (56 - bufferNdx)
176: : (120 - bufferNdx);
177:
178: // padding is alwas binary 1 followed by binary 0s
179: byte[] tail = new byte[padLen + 8];
180: tail[0] = (byte) 0x80;
181:
182: // append length before final transform:
183: // save number of bits, casting the long to an array of 8 bytes
184: // save low-order byte first.
185: for (int i = 0; i < 8; i++)
186: tail[padLen + i] = (byte) ((count * 8) >>> (8 * i));
187:
188: engineUpdate(tail, 0, tail.length);
189:
190: byte[] result = new byte[16];
191: // cast this MD4's context (array of 4 ints) into an array of 16 bytes.
192: for (int i = 0; i < 4; i++)
193: for (int j = 0; j < 4; j++)
194: result[i * 4 + j] = (byte) (context[i] >>> (8 * j));
195:
196: // reset the engine
197: engineReset();
198: return result;
199: }
200:
201: // own methods
202: //...........................................................................
203:
204: /**
205: * MD4 basic transformation.
206: * <p>
207: * Transforms context based on 512 bits from input block starting
208: * from the offset'th byte.
209: *
210: * @param block input sub-array.
211: * @param offset starting position of sub-array.
212: */
213: private void transform(byte[] block, int offset) {
214:
215: // encodes 64 bytes from input block into an array of 16 32-bit
216: // entities. Use A as a temp var.
217: for (int i = 0; i < 16; i++)
218: X[i] = (block[offset++] & 0xFF)
219: | (block[offset++] & 0xFF) << 8
220: | (block[offset++] & 0xFF) << 16
221: | (block[offset++] & 0xFF) << 24;
222:
223: int A = context[0];
224: int B = context[1];
225: int C = context[2];
226: int D = context[3];
227:
228: A = FF(A, B, C, D, X[0], 3);
229: D = FF(D, A, B, C, X[1], 7);
230: C = FF(C, D, A, B, X[2], 11);
231: B = FF(B, C, D, A, X[3], 19);
232: A = FF(A, B, C, D, X[4], 3);
233: D = FF(D, A, B, C, X[5], 7);
234: C = FF(C, D, A, B, X[6], 11);
235: B = FF(B, C, D, A, X[7], 19);
236: A = FF(A, B, C, D, X[8], 3);
237: D = FF(D, A, B, C, X[9], 7);
238: C = FF(C, D, A, B, X[10], 11);
239: B = FF(B, C, D, A, X[11], 19);
240: A = FF(A, B, C, D, X[12], 3);
241: D = FF(D, A, B, C, X[13], 7);
242: C = FF(C, D, A, B, X[14], 11);
243: B = FF(B, C, D, A, X[15], 19);
244:
245: A = GG(A, B, C, D, X[0], 3);
246: D = GG(D, A, B, C, X[4], 5);
247: C = GG(C, D, A, B, X[8], 9);
248: B = GG(B, C, D, A, X[12], 13);
249: A = GG(A, B, C, D, X[1], 3);
250: D = GG(D, A, B, C, X[5], 5);
251: C = GG(C, D, A, B, X[9], 9);
252: B = GG(B, C, D, A, X[13], 13);
253: A = GG(A, B, C, D, X[2], 3);
254: D = GG(D, A, B, C, X[6], 5);
255: C = GG(C, D, A, B, X[10], 9);
256: B = GG(B, C, D, A, X[14], 13);
257: A = GG(A, B, C, D, X[3], 3);
258: D = GG(D, A, B, C, X[7], 5);
259: C = GG(C, D, A, B, X[11], 9);
260: B = GG(B, C, D, A, X[15], 13);
261:
262: A = HH(A, B, C, D, X[0], 3);
263: D = HH(D, A, B, C, X[8], 9);
264: C = HH(C, D, A, B, X[4], 11);
265: B = HH(B, C, D, A, X[12], 15);
266: A = HH(A, B, C, D, X[2], 3);
267: D = HH(D, A, B, C, X[10], 9);
268: C = HH(C, D, A, B, X[6], 11);
269: B = HH(B, C, D, A, X[14], 15);
270: A = HH(A, B, C, D, X[1], 3);
271: D = HH(D, A, B, C, X[9], 9);
272: C = HH(C, D, A, B, X[5], 11);
273: B = HH(B, C, D, A, X[13], 15);
274: A = HH(A, B, C, D, X[3], 3);
275: D = HH(D, A, B, C, X[11], 9);
276: C = HH(C, D, A, B, X[7], 11);
277: B = HH(B, C, D, A, X[15], 15);
278:
279: context[0] += A;
280: context[1] += B;
281: context[2] += C;
282: context[3] += D;
283: }
284:
285: // The basic MD4 atomic functions.
286:
287: private int FF(int a, int b, int c, int d, int x, int s) {
288: int t = a + ((b & c) | (~b & d)) + x;
289: return t << s | t >>> (32 - s);
290: }
291:
292: private int GG(int a, int b, int c, int d, int x, int s) {
293: int t = a + ((b & (c | d)) | (c & d)) + x + 0x5A827999;
294: return t << s | t >>> (32 - s);
295: }
296:
297: private int HH(int a, int b, int c, int d, int x, int s) {
298: int t = a + (b ^ c ^ d) + x + 0x6ED9EBA1;
299: return t << s | t >>> (32 - s);
300: }
301: }
|