Source code: plugins/MsnEngine/MD5.java
1 /*
2 This file is part of DeXter - Java Internet Communication Solution
3 Copyright (c) 2002 Tobias Riemer
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20 package plugins.MsnEngine;
21
22 /*
23 * $Header: /cvsroot/jdexter/plugins/MsnEngine/MD5.java,v 1.3 2002/10/28 21:35:41 saintedlama Exp $
24 *
25 * MD5 in Java JDK Beta-2
26 * written Santeri Paavolainen, Helsinki Finland 1996
27 * (c) Santeri Paavolainen, Helsinki Finland 1996
28 *
29 * This library is free software; you can redistribute it and/or
30 * modify it under the terms of the GNU Library General Public
31 * License as published by the Free Software Foundation; either
32 * version 2 of the License, or (at your option) any later version.
33 *
34 * This library is distributed in the hope that it will be useful,
35 * but WITHOUT ANY WARRANTY; without even the implied warranty of
36 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
37 * Library General Public License for more details.
38 *
39 * You should have received a copy of the GNU Library General Public
40 * License along with this library; if not, write to the Free
41 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
42 *
43 * See http://www.cs.hut.fi/~santtu/java/ for more information on this
44 * class.
45 *
46 * This is rather straight re-implementation of the reference implementation
47 * given in RFC1321 by RSA.
48 *
49 * Passes MD5 test suite as defined in RFC1321.
50 *
51 *
52 * This Java class has been derived from the RSA Data Security, Inc. MD5
53 * Message-Digest Algorithm and its reference implementation.
54 *
55 *
56 * $Log: MD5.java,v $
57 * Revision 1.3 2002/10/28 21:35:41 saintedlama
58 *
59 * License Header inserted
60 *
61 * Revision 1.2 2002/10/27 14:44:32 saintedlama
62 *
63 * Made MD5State an inner Class of MD5
64 *
65 * Revision 1.1 2002/10/21 18:02:28 tobias_r
66 * *** empty log message ***
67 *
68 * Revision 1.1.1.1 2002/10/16 22:10:49 tobias_r
69 *
70 *
71 * Revision 1.5 1996/12/12 10:47:02 santtu
72 * Changed GPL to LGPL
73 *
74 * Revision 1.4 1996/12/12 10:30:02 santtu
75 * Some typos, State -> MD5State etc.
76 *
77 * Revision 1.3 1996/04/15 07:28:09 santtu
78 * Added GPL statemets, and RSA derivate stametemetsnnts.
79 *
80 * Revision 1.2 1996/03/04 08:05:48 santtu
81 * Added offsets to Update method
82 *
83 * Revision 1.1 1996/01/07 20:51:59 santtu
84 * Initial revision
85 *
86 */
87
88 /**
89 * Implementation of RSA's MD5 hash generator
90 *
91 * @version $Revision: 1.3 $
92 * @author Santeri Paavolainen <sjpaavol@cc.helsinki.fi>
93 */
94
95 public class MD5 {
96 /**
97 * MD5 state
98 */
99 MD5State state;
100
101 /**
102 * If Final() has been called, finals is set to the current finals
103 * state. Any Update() causes this to be set to null.
104 */
105 MD5State finals;
106
107 /**
108 * Padding for Final()
109 */
110 static byte padding[] = {
111 (byte) 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
112 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
113 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
114 };
115
116 /**
117 * Initialize MD5 internal state (object can be reused just by
118 * calling Init() after every Final()
119 */
120 public synchronized void Init() {
121 state = new MD5.MD5State();
122 finals = null;
123 }
124
125 /**
126 * Class constructor
127 */
128 public MD5() {
129 this.Init();
130 }
131
132 /**
133 * Initialize class, and update hash with ob.toString()
134 *
135 * @param ob Object, ob.toString() is used to update hash
136 * after initialization
137 */
138 public MD5(Object ob) {
139 this();
140 Update(ob.toString());
141 }
142
143 private int rotate_left(int x, int n) {
144 return (x << n) | (x >>> (32 - n));
145 }
146
147 /* I wonder how many loops and hoops you'll have to go through to
148 get unsigned add for longs in java */
149
150 private int uadd(int a, int b) {
151 long aa, bb;
152 aa = ((long) a) & 0xffffffffL;
153 bb = ((long) b) & 0xffffffffL;
154
155 aa += bb;
156
157 return (int) (aa & 0xffffffffL);
158 }
159
160 private int uadd(int a, int b, int c) {
161 return uadd(uadd(a, b), c);
162 }
163
164 private int uadd(int a, int b, int c, int d) {
165 return uadd(uadd(a, b, c), d);
166 }
167
168 private int FF(int a, int b, int c, int d, int x, int s, int ac) {
169 a = uadd(a, ((b & c) | (~b & d)), x, ac);
170 return uadd(rotate_left(a, s), b);
171 }
172
173 private int GG(int a, int b, int c, int d, int x, int s, int ac) {
174 a = uadd(a, ((b & d) | (c & ~d)), x, ac);
175 return uadd(rotate_left(a, s), b);
176 }
177
178 private int HH(int a, int b, int c, int d, int x, int s, int ac) {
179 a = uadd(a, (b ^ c ^ d), x, ac);
180 return uadd(rotate_left(a, s) , b);
181 }
182
183 private int II(int a, int b, int c, int d, int x, int s, int ac) {
184 a = uadd(a, (c ^ (b | ~d)), x, ac);
185 return uadd(rotate_left(a, s), b);
186 }
187
188 private int[] Decode(byte buffer[], int len, int shift) {
189 int out[];
190 int i, j;
191
192 out = new int[16];
193
194 for (i = j = 0; j < len; i++, j += 4) {
195 out[i] = ((int) (buffer[j + shift] & 0xff)) |
196 (((int) (buffer[j + 1 + shift] & 0xff)) << 8) |
197 (((int) (buffer[j + 2 + shift] & 0xff)) << 16) |
198 (((int) (buffer[j + 3 + shift] & 0xff)) << 24);
199
200 /* System.out.println("out[" + i + "] = \t" +
201 ((int) buffer[j + 0 + shift] & 0xff) + "\t|\t" +
202 ((int) buffer[j + 1 + shift] & 0xff) + "\t|\t" +
203 ((int) buffer[j + 2 + shift] & 0xff) + "\t|\t" +
204 ((int) buffer[j + 3 + shift] & 0xff));*/
205 }
206
207 return out;
208 }
209
210 private void Transform(MD5State state, byte buffer[], int shift) {
211 int
212 a = state.state[0],
213 b = state.state[1],
214 c = state.state[2],
215 d = state.state[3],
216 x[];
217
218 x = Decode(buffer, 64, shift);
219
220 /* Round 1 */
221 a = FF(a, b, c, d, x[ 0], 7, 0xd76aa478); /* 1 */
222 d = FF(d, a, b, c, x[ 1], 12, 0xe8c7b756); /* 2 */
223 c = FF(c, d, a, b, x[ 2], 17, 0x242070db); /* 3 */
224 b = FF(b, c, d, a, x[ 3], 22, 0xc1bdceee); /* 4 */
225 a = FF(a, b, c, d, x[ 4], 7, 0xf57c0faf); /* 5 */
226 d = FF(d, a, b, c, x[ 5], 12, 0x4787c62a); /* 6 */
227 c = FF(c, d, a, b, x[ 6], 17, 0xa8304613); /* 7 */
228 b = FF(b, c, d, a, x[ 7], 22, 0xfd469501); /* 8 */
229 a = FF(a, b, c, d, x[ 8], 7, 0x698098d8); /* 9 */
230 d = FF(d, a, b, c, x[ 9], 12, 0x8b44f7af); /* 10 */
231 c = FF(c, d, a, b, x[10], 17, 0xffff5bb1); /* 11 */
232 b = FF(b, c, d, a, x[11], 22, 0x895cd7be); /* 12 */
233 a = FF(a, b, c, d, x[12], 7, 0x6b901122); /* 13 */
234 d = FF(d, a, b, c, x[13], 12, 0xfd987193); /* 14 */
235 c = FF(c, d, a, b, x[14], 17, 0xa679438e); /* 15 */
236 b = FF(b, c, d, a, x[15], 22, 0x49b40821); /* 16 */
237
238 /* Round 2 */
239 a = GG(a, b, c, d, x[ 1], 5, 0xf61e2562); /* 17 */
240 d = GG(d, a, b, c, x[ 6], 9, 0xc040b340); /* 18 */
241 c = GG(c, d, a, b, x[11], 14, 0x265e5a51); /* 19 */
242 b = GG(b, c, d, a, x[ 0], 20, 0xe9b6c7aa); /* 20 */
243 a = GG(a, b, c, d, x[ 5], 5, 0xd62f105d); /* 21 */
244 d = GG(d, a, b, c, x[10], 9, 0x2441453); /* 22 */
245 c = GG(c, d, a, b, x[15], 14, 0xd8a1e681); /* 23 */
246 b = GG(b, c, d, a, x[ 4], 20, 0xe7d3fbc8); /* 24 */
247 a = GG(a, b, c, d, x[ 9], 5, 0x21e1cde6); /* 25 */
248 d = GG(d, a, b, c, x[14], 9, 0xc33707d6); /* 26 */
249 c = GG(c, d, a, b, x[ 3], 14, 0xf4d50d87); /* 27 */
250 b = GG(b, c, d, a, x[ 8], 20, 0x455a14ed); /* 28 */
251 a = GG(a, b, c, d, x[13], 5, 0xa9e3e905); /* 29 */
252 d = GG(d, a, b, c, x[ 2], 9, 0xfcefa3f8); /* 30 */
253 c = GG(c, d, a, b, x[ 7], 14, 0x676f02d9); /* 31 */
254 b = GG(b, c, d, a, x[12], 20, 0x8d2a4c8a); /* 32 */
255
256 /* Round 3 */
257 a = HH(a, b, c, d, x[ 5], 4, 0xfffa3942); /* 33 */
258 d = HH(d, a, b, c, x[ 8], 11, 0x8771f681); /* 34 */
259 c = HH(c, d, a, b, x[11], 16, 0x6d9d6122); /* 35 */
260 b = HH(b, c, d, a, x[14], 23, 0xfde5380c); /* 36 */
261 a = HH(a, b, c, d, x[ 1], 4, 0xa4beea44); /* 37 */
262 d = HH(d, a, b, c, x[ 4], 11, 0x4bdecfa9); /* 38 */
263 c = HH(c, d, a, b, x[ 7], 16, 0xf6bb4b60); /* 39 */
264 b = HH(b, c, d, a, x[10], 23, 0xbebfbc70); /* 40 */
265 a = HH(a, b, c, d, x[13], 4, 0x289b7ec6); /* 41 */
266 d = HH(d, a, b, c, x[ 0], 11, 0xeaa127fa); /* 42 */
267 c = HH(c, d, a, b, x[ 3], 16, 0xd4ef3085); /* 43 */
268 b = HH(b, c, d, a, x[ 6], 23, 0x4881d05); /* 44 */
269 a = HH(a, b, c, d, x[ 9], 4, 0xd9d4d039); /* 45 */
270 d = HH(d, a, b, c, x[12], 11, 0xe6db99e5); /* 46 */
271 c = HH(c, d, a, b, x[15], 16, 0x1fa27cf8); /* 47 */
272 b = HH(b, c, d, a, x[ 2], 23, 0xc4ac5665); /* 48 */
273
274 /* Round 4 */
275 a = II(a, b, c, d, x[ 0], 6, 0xf4292244); /* 49 */
276 d = II(d, a, b, c, x[ 7], 10, 0x432aff97); /* 50 */
277 c = II(c, d, a, b, x[14], 15, 0xab9423a7); /* 51 */
278 b = II(b, c, d, a, x[ 5], 21, 0xfc93a039); /* 52 */
279 a = II(a, b, c, d, x[12], 6, 0x655b59c3); /* 53 */
280 d = II(d, a, b, c, x[ 3], 10, 0x8f0ccc92); /* 54 */
281 c = II(c, d, a, b, x[10], 15, 0xffeff47d); /* 55 */
282 b = II(b, c, d, a, x[ 1], 21, 0x85845dd1); /* 56 */
283 a = II(a, b, c, d, x[ 8], 6, 0x6fa87e4f); /* 57 */
284 d = II(d, a, b, c, x[15], 10, 0xfe2ce6e0); /* 58 */
285 c = II(c, d, a, b, x[ 6], 15, 0xa3014314); /* 59 */
286 b = II(b, c, d, a, x[13], 21, 0x4e0811a1); /* 60 */
287 a = II(a, b, c, d, x[ 4], 6, 0xf7537e82); /* 61 */
288 d = II(d, a, b, c, x[11], 10, 0xbd3af235); /* 62 */
289 c = II(c, d, a, b, x[ 2], 15, 0x2ad7d2bb); /* 63 */
290 b = II(b, c, d, a, x[ 9], 21, 0xeb86d391); /* 64 */
291
292 state.state[0] += a;
293 state.state[1] += b;
294 state.state[2] += c;
295 state.state[3] += d;
296 }
297
298 /**
299 * Updates hash with the bytebuffer given (using at maximum length bytes from
300 * that buffer)
301 *
302 * @param state Which state is updated
303 * @param buffer Array of bytes to be hashed
304 * @param offset Offset to buffer array
305 * @param length Use at maximum `length' bytes (absolute
306 * maximum is buffer.length)
307 */
308 public void Update(MD5State stat, byte buffer[], int offset, int length) {
309 int index, partlen, i, start;
310
311 /* System.out.print("Offset = " + offset + "\tLength = " + length + "\t");
312 System.out.print("Buffer = ");
313 for (i = 0; i < buffer.length; i++)
314 System.out.print((int) (buffer[i] & 0xff) + " ");
315 System.out.print("\n");*/
316
317 finals = null;
318
319 /* Length can be told to be shorter, but not inter */
320 if ((length - offset)> buffer.length)
321 length = buffer.length - offset;
322
323 /* compute number of bytes mod 64 */
324 index = (int) (stat.count[0] >>> 3) & 0x3f;
325
326 if ((stat.count[0] += (length << 3)) <
327 (length << 3))
328 stat.count[1]++;
329
330 stat.count[1] += length >>> 29;
331
332 partlen = 64 - index;
333
334 if (length >= partlen) {
335 for (i = 0; i < partlen; i++)
336 stat.buffer[i + index] = buffer[i + offset];
337
338 Transform(stat, stat.buffer, 0);
339
340 for (i = partlen; (i + 63) < length; i+= 64)
341 Transform(stat, buffer, i);
342
343 index = 0;
344 } else
345 i = 0;
346
347 /* buffer remaining input */
348 if (i < length) {
349 start = i;
350 for (; i < length; i++)
351 stat.buffer[index + i - start] = buffer[i + offset];
352 }
353 }
354
355 /*
356 * Update()s for other datatypes than byte[] also. Update(byte[], int)
357 * is only the main driver.
358 */
359
360 /**
361 * Plain update, updates this object
362 */
363
364 public void Update(byte buffer[], int offset, int length) {
365 Update(this.state, buffer, offset, length);
366 }
367
368 public void Update(byte buffer[], int length) {
369 Update(this.state, buffer, 0, length);
370 }
371
372 /**
373 * Updates hash with given array of bytes
374 *
375 * @param buffer Array of bytes to use for updating the hash
376 */
377 public void Update(byte buffer[]) {
378 Update(buffer, 0, buffer.length);
379 }
380
381 /**
382 * Updates hash with a single byte
383 *
384 * @param b Single byte to update the hash
385 */
386 public void Update(byte b) {
387 byte buffer[] = new byte[1];
388 buffer[0] = b;
389
390 Update(buffer, 1);
391 }
392
393 /**
394 * Update buffer with given string.
395 *
396 * @param s String to be update to hash (is used as
397 * s.getBytes())
398 */
399 public void Update(String s) {
400 byte chars[];
401
402 chars = new byte[s.length()];
403 // tobias
404 chars = s.getBytes();
405 // s.getBytes(0, s.length(), chars, 0);
406
407 Update(chars, chars.length);
408 }
409
410 /**
411 * Update buffer with a single integer (only & 0xff part is used,
412 * as a byte)
413 *
414 * @param i Integer value, which is then converted to
415 * byte as i & 0xff
416 */
417
418 public void Update(int i) {
419 Update((byte) (i & 0xff));
420 }
421
422 private byte[] Encode(int input[], int len) {
423 int i, j;
424 byte out[];
425
426 out = new byte[len];
427
428 for (i = j = 0; j < len; i++, j += 4) {
429 out[j] = (byte) (input[i] & 0xff);
430 out[j + 1] = (byte) ((input[i] >>> 8) & 0xff);
431 out[j + 2] = (byte) ((input[i] >>> 16) & 0xff);
432 out[j + 3] = (byte) ((input[i] >>> 24) & 0xff);
433 }
434
435 return out;
436 }
437
438 /**
439 * Returns array of bytes (16 bytes) representing hash as of the
440 * current state of this object. Note: getting a hash does not
441 * invalidate the hash object, it only creates a copy of the real
442 * state which is finalized.
443 *
444 * @return Array of 16 bytes, the hash of all updated bytes
445 */
446 public synchronized byte[] Final() {
447 byte bits[];
448 int index, padlen;
449 MD5State fin;
450
451 if (finals == null) {
452 fin = new MD5.MD5State(state);
453
454 bits = Encode(fin.count, 8);
455
456 index = (int) ((fin.count[0] >>> 3) & 0x3f);
457 padlen = (index < 56) ? (56 - index) : (120 - index);
458
459 Update(fin, padding, 0, padlen);
460 /**/
461 Update(fin, bits, 0, 8);
462
463 /* Update() sets finalds to null */
464 finals = fin;
465 }
466
467 return Encode(finals.state, 16);
468 }
469
470 /**
471 * Turns array of bytes into string representing each byte as
472 * unsigned hex number.
473 *
474 * @param hash Array of bytes to convert to hex-string
475 * @return Generated hex string
476 */
477 public static String asHex(byte hash[]) {
478 StringBuffer buf = new StringBuffer(hash.length * 2);
479 int i;
480
481 for (i = 0; i < hash.length; i++) {
482 if (((int) hash[i] & 0xff) < 0x10)
483 buf.append("0");
484
485 buf.append(Long.toString((int) hash[i] & 0xff, 16));
486 }
487
488 return buf.toString();
489 }
490
491 /**
492 * Returns 32-character hex representation of this objects hash
493 *
494 * @return String of this object's hash
495 */
496 public String asHex() {
497 return asHex(this.Final());
498 }
499
500 /**
501 * Contains internal state of the MD5 class
502 */
503 private class MD5State {
504 /**
505 * 128-byte state
506 */
507 int state[];
508
509 /**
510 * 64-bit character count (could be true Java long?)
511 */
512 int count[];
513
514 /**
515 * 64-byte buffer (512 bits) for storing to-be-hashed characters
516 */
517 byte buffer[];
518
519 public MD5State() {
520 buffer = new byte[64];
521 count = new int[2];
522 state = new int[4];
523
524 state[0] = 0x67452301;
525 state[1] = 0xefcdab89;
526 state[2] = 0x98badcfe;
527 state[3] = 0x10325476;
528
529 count[0] = count[1] = 0;
530 }
531
532 /** Create this State as a copy of another state */
533 public MD5State(MD5State from) {
534 this();
535
536 int i;
537
538 for (i = 0; i < buffer.length; i++)
539 this.buffer[i] = from.buffer[i];
540
541 for (i = 0; i < state.length; i++)
542 this.state[i] = from.state[i];
543
544 for (i = 0; i < count.length; i++)
545 this.count[i] = from.count[i];
546 }
547 };
548 }