001: package com.knowgate.misc;
002:
003: import com.knowgate.debug.DebugFile;
004:
005: /*
006: * $Header: /cvsroot/hipergate/backend/src/com/knowgate/misc/MD5.java,v 1.1.1.1 2005/06/23 15:15:08 smontoro Exp $
007: *
008: * MD5 in Java JDK Beta-2
009: * written Santeri Paavolainen, Helsinki Finland 1996
010: * (c) Santeri Paavolainen, Helsinki Finland 1996
011: *
012: * This library is free software; you can redistribute it and/or
013: * modify it under the terms of the GNU Library General Public
014: * License as published by the Free Software Foundation; either
015: * version 2 of the License, or (at your option) any later version.
016: *
017: * This library is distributed in the hope that it will be useful,
018: * but WITHOUT ANY WARRANTY; without even the implied warranty of
019: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
020: * Library General Public License for more details.
021: *
022: * You should have received a copy of the GNU Library General Public
023: * License along with this library; if not, write to the Free
024: * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
025: *
026: * See http://www.cs.hut.fi/~santtu/java/ for more information on this
027: * class.
028: *
029: * This is rather straight re-implementation of the reference implementation
030: * given in RFC1321 by RSA.
031: *
032: * Passes MD5 test suite as defined in RFC1321.
033: *
034: *
035: * This Java class has been derived from the RSA Data Security, Inc. MD5
036: * Message-Digest Algorithm and its reference implementation.
037: *
038: * Revision 1.1 1996/01/07 20:51:59 santtu
039: * Initial revision
040: *
041: */
042:
043: /**
044: * Contains internal state of the MD5 class
045: */
046:
047: class MD5State {
048: /**
049: * 128-byte state
050: */
051: int state[];
052:
053: /**
054: * 64-bit character count (could be true Java long?)
055: */
056: int count[];
057:
058: /**
059: * 64-byte buffer (512 bits) for storing to-be-hashed characters
060: */
061: byte buffer[];
062:
063: public MD5State() {
064: buffer = new byte[64];
065: count = new int[2];
066: state = new int[4];
067:
068: state[0] = 0x67452301;
069: state[1] = 0xefcdab89;
070: state[2] = 0x98badcfe;
071: state[3] = 0x10325476;
072:
073: count[0] = count[1] = 0;
074: }
075:
076: /** Create this State as a copy of another state */
077: public MD5State(MD5State from) {
078: this ();
079:
080: int i;
081:
082: for (i = 0; i < buffer.length; i++)
083: this .buffer[i] = from.buffer[i];
084:
085: for (i = 0; i < state.length; i++)
086: this .state[i] = from.state[i];
087:
088: for (i = 0; i < count.length; i++)
089: this .count[i] = from.count[i];
090: }
091: }
092:
093: /**
094: * Implementation of RSA's MD5 hash generator
095: *
096: * @version $Revision: 1.1.1.1 $
097: * @author Santeri Paavolainen <sjpaavol@cc.helsinki.fi>
098: */
099:
100: public class MD5 {
101: /**
102: * MD5 state
103: */
104: MD5State state;
105:
106: /**
107: * If Final() has been called, finals is set to the current finals
108: * state. Any Update() causes this to be set to null.
109: */
110: MD5State finals;
111:
112: /**
113: * Padding for Final()
114: */
115: static byte padding[] = { (byte) 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0,
116: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
117: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
118: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
119:
120: /**
121: * Initialize MD5 internal state (object can be reused just by
122: * calling Init() after every Final()
123: */
124: public synchronized void Init() {
125: state = new MD5State();
126: finals = null;
127: }
128:
129: /**
130: * Class constructor
131: */
132: public MD5() {
133: this .Init();
134: }
135:
136: /**
137: * Initialize class, and update hash with ob.toString()
138: *
139: * @param ob Object, ob.toString() is used to update hash
140: * after initialization
141: */
142: public MD5(Object ob) {
143: this ();
144: Update(ob.toString());
145: }
146:
147: private int rotate_left(int x, int n) {
148: return (x << n) | (x >>> (32 - n));
149: }
150:
151: /* I wonder how many loops and hoops you'll have to go through to
152: get unsigned add for longs in java */
153:
154: private int uadd(int a, int b) {
155: long aa, bb;
156: aa = ((long) a) & 0xffffffffL;
157: bb = ((long) b) & 0xffffffffL;
158:
159: aa += bb;
160:
161: return (int) (aa & 0xffffffffL);
162: }
163:
164: private int uadd(int a, int b, int c) {
165: return uadd(uadd(a, b), c);
166: }
167:
168: private int uadd(int a, int b, int c, int d) {
169: return uadd(uadd(a, b, c), d);
170: }
171:
172: private int FF(int a, int b, int c, int d, int x, int s, int ac) {
173: a = uadd(a, ((b & c) | (~b & d)), x, ac);
174: return uadd(rotate_left(a, s), b);
175: }
176:
177: private int GG(int a, int b, int c, int d, int x, int s, int ac) {
178: a = uadd(a, ((b & d) | (c & ~d)), x, ac);
179: return uadd(rotate_left(a, s), b);
180: }
181:
182: private int HH(int a, int b, int c, int d, int x, int s, int ac) {
183: a = uadd(a, (b ^ c ^ d), x, ac);
184: return uadd(rotate_left(a, s), b);
185: }
186:
187: private int II(int a, int b, int c, int d, int x, int s, int ac) {
188: a = uadd(a, (c ^ (b | ~d)), x, ac);
189: return uadd(rotate_left(a, s), b);
190: }
191:
192: private int[] Decode(byte buffer[], int len, int shift) {
193: int out[];
194: int i, j;
195:
196: out = new int[16];
197:
198: for (i = j = 0; j < len; i++, j += 4) {
199: out[i] = ((int) (buffer[j + shift] & 0xff))
200: | (((int) (buffer[j + 1 + shift] & 0xff)) << 8)
201: | (((int) (buffer[j + 2 + shift] & 0xff)) << 16)
202: | (((int) (buffer[j + 3 + shift] & 0xff)) << 24);
203:
204: /* System.out.println("out[" + i + "] = \t" +
205: ((int) buffer[j + 0 + shift] & 0xff) + "\t|\t" +
206: ((int) buffer[j + 1 + shift] & 0xff) + "\t|\t" +
207: ((int) buffer[j + 2 + shift] & 0xff) + "\t|\t" +
208: ((int) buffer[j + 3 + shift] & 0xff));*/
209: }
210:
211: return out;
212: }
213:
214: private void Transform(MD5State state, byte buffer[], int shift) {
215: int a = state.state[0], b = state.state[1], c = state.state[2], d = state.state[3], x[];
216:
217: x = Decode(buffer, 64, shift);
218:
219: /* Round 1 */
220: a = FF(a, b, c, d, x[0], 7, 0xd76aa478); /* 1 */
221: d = FF(d, a, b, c, x[1], 12, 0xe8c7b756); /* 2 */
222: c = FF(c, d, a, b, x[2], 17, 0x242070db); /* 3 */
223: b = FF(b, c, d, a, x[3], 22, 0xc1bdceee); /* 4 */
224: a = FF(a, b, c, d, x[4], 7, 0xf57c0faf); /* 5 */
225: d = FF(d, a, b, c, x[5], 12, 0x4787c62a); /* 6 */
226: c = FF(c, d, a, b, x[6], 17, 0xa8304613); /* 7 */
227: b = FF(b, c, d, a, x[7], 22, 0xfd469501); /* 8 */
228: a = FF(a, b, c, d, x[8], 7, 0x698098d8); /* 9 */
229: d = FF(d, a, b, c, x[9], 12, 0x8b44f7af); /* 10 */
230: c = FF(c, d, a, b, x[10], 17, 0xffff5bb1); /* 11 */
231: b = FF(b, c, d, a, x[11], 22, 0x895cd7be); /* 12 */
232: a = FF(a, b, c, d, x[12], 7, 0x6b901122); /* 13 */
233: d = FF(d, a, b, c, x[13], 12, 0xfd987193); /* 14 */
234: c = FF(c, d, a, b, x[14], 17, 0xa679438e); /* 15 */
235: b = FF(b, c, d, a, x[15], 22, 0x49b40821); /* 16 */
236:
237: /* Round 2 */
238: a = GG(a, b, c, d, x[1], 5, 0xf61e2562); /* 17 */
239: d = GG(d, a, b, c, x[6], 9, 0xc040b340); /* 18 */
240: c = GG(c, d, a, b, x[11], 14, 0x265e5a51); /* 19 */
241: b = GG(b, c, d, a, x[0], 20, 0xe9b6c7aa); /* 20 */
242: a = GG(a, b, c, d, x[5], 5, 0xd62f105d); /* 21 */
243: d = GG(d, a, b, c, x[10], 9, 0x2441453); /* 22 */
244: c = GG(c, d, a, b, x[15], 14, 0xd8a1e681); /* 23 */
245: b = GG(b, c, d, a, x[4], 20, 0xe7d3fbc8); /* 24 */
246: a = GG(a, b, c, d, x[9], 5, 0x21e1cde6); /* 25 */
247: d = GG(d, a, b, c, x[14], 9, 0xc33707d6); /* 26 */
248: c = GG(c, d, a, b, x[3], 14, 0xf4d50d87); /* 27 */
249: b = GG(b, c, d, a, x[8], 20, 0x455a14ed); /* 28 */
250: a = GG(a, b, c, d, x[13], 5, 0xa9e3e905); /* 29 */
251: d = GG(d, a, b, c, x[2], 9, 0xfcefa3f8); /* 30 */
252: c = GG(c, d, a, b, x[7], 14, 0x676f02d9); /* 31 */
253: b = GG(b, c, d, a, x[12], 20, 0x8d2a4c8a); /* 32 */
254:
255: /* Round 3 */
256: a = HH(a, b, c, d, x[5], 4, 0xfffa3942); /* 33 */
257: d = HH(d, a, b, c, x[8], 11, 0x8771f681); /* 34 */
258: c = HH(c, d, a, b, x[11], 16, 0x6d9d6122); /* 35 */
259: b = HH(b, c, d, a, x[14], 23, 0xfde5380c); /* 36 */
260: a = HH(a, b, c, d, x[1], 4, 0xa4beea44); /* 37 */
261: d = HH(d, a, b, c, x[4], 11, 0x4bdecfa9); /* 38 */
262: c = HH(c, d, a, b, x[7], 16, 0xf6bb4b60); /* 39 */
263: b = HH(b, c, d, a, x[10], 23, 0xbebfbc70); /* 40 */
264: a = HH(a, b, c, d, x[13], 4, 0x289b7ec6); /* 41 */
265: d = HH(d, a, b, c, x[0], 11, 0xeaa127fa); /* 42 */
266: c = HH(c, d, a, b, x[3], 16, 0xd4ef3085); /* 43 */
267: b = HH(b, c, d, a, x[6], 23, 0x4881d05); /* 44 */
268: a = HH(a, b, c, d, x[9], 4, 0xd9d4d039); /* 45 */
269: d = HH(d, a, b, c, x[12], 11, 0xe6db99e5); /* 46 */
270: c = HH(c, d, a, b, x[15], 16, 0x1fa27cf8); /* 47 */
271: b = HH(b, c, d, a, x[2], 23, 0xc4ac5665); /* 48 */
272:
273: /* Round 4 */
274: a = II(a, b, c, d, x[0], 6, 0xf4292244); /* 49 */
275: d = II(d, a, b, c, x[7], 10, 0x432aff97); /* 50 */
276: c = II(c, d, a, b, x[14], 15, 0xab9423a7); /* 51 */
277: b = II(b, c, d, a, x[5], 21, 0xfc93a039); /* 52 */
278: a = II(a, b, c, d, x[12], 6, 0x655b59c3); /* 53 */
279: d = II(d, a, b, c, x[3], 10, 0x8f0ccc92); /* 54 */
280: c = II(c, d, a, b, x[10], 15, 0xffeff47d); /* 55 */
281: b = II(b, c, d, a, x[1], 21, 0x85845dd1); /* 56 */
282: a = II(a, b, c, d, x[8], 6, 0x6fa87e4f); /* 57 */
283: d = II(d, a, b, c, x[15], 10, 0xfe2ce6e0); /* 58 */
284: c = II(c, d, a, b, x[6], 15, 0xa3014314); /* 59 */
285: b = II(b, c, d, a, x[13], 21, 0x4e0811a1); /* 60 */
286: a = II(a, b, c, d, x[4], 6, 0xf7537e82); /* 61 */
287: d = II(d, a, b, c, x[11], 10, 0xbd3af235); /* 62 */
288: c = II(c, d, a, b, x[2], 15, 0x2ad7d2bb); /* 63 */
289: b = II(b, c, d, a, x[9], 21, 0xeb86d391); /* 64 */
290:
291: state.state[0] += a;
292: state.state[1] += b;
293: state.state[2] += c;
294: state.state[3] += d;
295: }
296:
297: /**
298: * Updates hash with the bytebuffer given (using at maximum length bytes from
299: * that buffer)
300: *
301: * @param state Which state is updated
302: * @param buffer Array of bytes to be hashed
303: * @param offset Offset to buffer array
304: * @param length Use at maximum `length' bytes (absolute
305: * maximum is buffer.length)
306: */
307: public void Update(MD5State stat, byte buffer[], int offset,
308: int length) throws NullPointerException {
309: int index, partlen, i, start;
310:
311: if (null == buffer)
312: throw new NullPointerException(
313: "Array of bytes to be hashed may not be null");
314:
315: if (DebugFile.trace) {
316: DebugFile.writeln("Begin MD5.Update([MD5State],byte[],"
317: + String.valueOf(offset) + ","
318: + String.valueOf(length) + ")");
319: DebugFile.incIdent();
320: }
321:
322: finals = null;
323:
324: /* Length can be told to be shorter, but not inter */
325: if ((length - offset) > buffer.length)
326: length = buffer.length - offset;
327:
328: /* compute number of bytes mod 64 */
329: index = (int) (stat.count[0] >>> 3) & 0x3f;
330:
331: if ((stat.count[0] += (length << 3)) < (length << 3))
332: stat.count[1]++;
333:
334: stat.count[1] += length >>> 29;
335:
336: partlen = 64 - index;
337:
338: if (length >= partlen) {
339: for (i = 0; i < partlen; i++)
340: stat.buffer[i + index] = buffer[i + offset];
341:
342: Transform(stat, stat.buffer, 0);
343:
344: for (i = partlen; (i + 63) < length; i += 64)
345: Transform(stat, buffer, i);
346:
347: index = 0;
348: } else
349: i = 0;
350:
351: /* buffer remaining input */
352: if (i < length) {
353: start = i;
354: for (; i < length; i++)
355: stat.buffer[index + i - start] = buffer[i + offset];
356: }
357:
358: if (DebugFile.trace) {
359: DebugFile.decIdent();
360: DebugFile.writeln("End MD5.Update()");
361: }
362: } // Update
363:
364: /*
365: * Update()s for other datatypes than byte[] also. Update(byte[], int)
366: * is only the main driver.
367: */
368:
369: /**
370: * Plain update, updates this object
371: */
372:
373: public void Update(byte buffer[], int offset, int length) {
374: Update(this .state, buffer, offset, length);
375: }
376:
377: public void Update(byte buffer[], int length) {
378: Update(this .state, buffer, 0, length);
379: }
380:
381: /**
382: * Updates hash with given array of bytes
383: *
384: * @param buffer Array of bytes to use for updating the hash
385: */
386: public void Update(byte buffer[]) throws NullPointerException {
387: if (null == buffer)
388: throw new NullPointerException(
389: "Array of bytes to be hashed may not be null");
390:
391: Update(buffer, 0, buffer.length);
392: }
393:
394: /**
395: * Updates hash with a single byte
396: *
397: * @param b Single byte to update the hash
398: */
399: public void Update(byte b) {
400: byte buffer[] = new byte[1];
401: buffer[0] = b;
402:
403: Update(buffer, 1);
404: }
405:
406: /**
407: * Update buffer with given string.
408: *
409: * @param s String to be update to hash (is used as
410: * s.getBytes())
411: */
412: public void Update(String s) {
413: byte chars[];
414:
415: // chars = new byte[s.length()];
416: // s.getBytes(0, s.length(), chars, 0);
417: try {
418: chars = s.getBytes("UTF-8");
419: } catch (java.io.UnsupportedEncodingException ex) {
420: // Should never happen
421: ex.printStackTrace();
422: chars = new byte[1];
423: }
424:
425: Update(chars, chars.length);
426: }
427:
428: /**
429: * Update buffer with a single integer (only & 0xff part is used,
430: * as a byte)
431: *
432: * @param i Integer value, which is then converted to
433: * byte as i & 0xff
434: */
435:
436: public void Update(int i) {
437: Update((byte) (i & 0xff));
438: }
439:
440: private byte[] Encode(int input[], int len) {
441: int i, j;
442: byte out[];
443:
444: out = new byte[len];
445:
446: for (i = j = 0; j < len; i++, j += 4) {
447: out[j] = (byte) (input[i] & 0xff);
448: out[j + 1] = (byte) ((input[i] >>> 8) & 0xff);
449: out[j + 2] = (byte) ((input[i] >>> 16) & 0xff);
450: out[j + 3] = (byte) ((input[i] >>> 24) & 0xff);
451: }
452:
453: return out;
454: }
455:
456: /**
457: * Returns array of bytes (16 bytes) representing hash as of the
458: * current state of this object. Note: getting a hash does not
459: * invalidate the hash object, it only creates a copy of the real
460: * state which is finalized.
461: *
462: * @return Array of 16 bytes, the hash of all updated bytes
463: */
464: public synchronized byte[] Final() {
465: byte bits[];
466: int index, padlen;
467: MD5State fin;
468:
469: if (finals == null) {
470: fin = new MD5State(state);
471:
472: bits = Encode(fin.count, 8);
473:
474: index = (int) ((fin.count[0] >>> 3) & 0x3f);
475: padlen = (index < 56) ? (56 - index) : (120 - index);
476:
477: Update(fin, padding, 0, padlen);
478: /**/
479: Update(fin, bits, 0, 8);
480:
481: /* Update() sets finalds to null */
482: finals = fin;
483: }
484:
485: byte[] byRetArray = Encode(finals.state, 16);
486:
487: if (DebugFile.trace)
488: DebugFile.writeln("MD5.Final() : "
489: + Gadgets.toHexString(byRetArray));
490:
491: return byRetArray;
492: }
493:
494: /**
495: * Turns array of bytes into string representing each byte as
496: * unsigned hex number.
497: *
498: * @param hash Array of bytes to convert to hex-string
499: * @return Generated hex string
500: */
501: public static String asHex(byte hash[]) {
502: StringBuffer buf = new StringBuffer(hash.length * 2);
503: int i;
504:
505: for (i = 0; i < hash.length; i++) {
506: if (((int) hash[i] & 0xff) < 0x10)
507: buf.append("0");
508:
509: buf.append(Long.toString((int) hash[i] & 0xff, 16));
510: }
511:
512: return buf.toString();
513: }
514:
515: /**
516: * Returns 32-character hex representation of this objects hash
517: *
518: * @return String of this object's hash
519: */
520: public String asHex() {
521: return asHex(this.Final());
522: }
523: }
|