001: /*
002: * MD5 implementation
003: * written Santeri Paavolainen, Helsinki Finland 1996
004: * (c) Santeri Paavolainen, Helsinki Finland 1996
005: * modifications Copyright (C) 2002-2004 Stephen Ostermiller
006: * http://ostermiller.org/contact.pl?regarding=Java+Utilities
007: *
008: * This program is free software; you can redistribute it and/or modify
009: * it under the terms of the GNU General Public License as published by
010: * the Free Software Foundation; either version 2 of the License, or
011: * (at your option) any later version.
012: *
013: * This program is distributed in the hope that it will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016: * GNU General Public License for more details.
017: *
018: * See COPYING.TXT for details.
019: *
020: * The original work by Santeri Paavolainen can be found at
021: * http://www.helsinki.fi/~sjpaavol/programs/md5/
022: *
023: * This Java class has been derived from the RSA Data Security, Inc. MD5
024: * Message-Digest Algorithm and its reference implementation.
025: */
026: package org.claros.chat.utility;
027:
028: import java.io.*;
029:
030: /**
031: * MD5 hash generator.
032: * More information about this class is available from <a target="_top" href=
033: * "http://ostermiller.org/utils/MD5.html">ostermiller.org</a>.
034: * <p>
035: * This class takes as input a message of arbitrary length and produces
036: * as output a 128-bit "fingerprint" or "message digest" of the input.
037: * It is conjectured that it is computationally infeasible to produce
038: * two messages having the same message digest, or to produce any
039: * message having a given pre-specified target message digest. The MD5
040: * algorithm is intended for digital signature applications, where a
041: * large file must be "compressed" in a secure manner before being
042: * encrypted with a private (secret) key under a public-key cryptosystem
043: * such as RSA.
044: * <p>
045: * For more information see RFC1321.
046: *
047: * @see MD5OutputStream
048: * @see MD5InputStream
049: *
050: * @author Santeri Paavolainen http://www.helsinki.fi/~sjpaavol/programs/md5/
051: * @author Stephen Ostermiller http://ostermiller.org/contact.pl?regarding=Java+Utilities
052: * @since ostermillerutils 1.00.00
053: */
054: public class MD5 {
055:
056: /**
057: * Class constructor
058: *
059: * @since ostermillerutils 1.00.00
060: */
061: public MD5() {
062: reset();
063: }
064:
065: /**
066: * Command line program that will take files as arguments
067: * and output the MD5 sum for each file.
068: *
069: * @param args command line arguments
070: *
071: * @since ostermillerutils 1.00.00
072: */
073: public static void main(String[] args) {
074: if (args.length == 0) {
075: System.err.println("Please specify a file.");
076: } else {
077: for (int i = 0; i < args.length; i++) {
078: try {
079: System.out.println(MD5.getHashString(new File(
080: args[i]))
081: + " " + args[i]);
082: } catch (IOException x) {
083: System.err.println(x.getMessage());
084: }
085: }
086: }
087: }
088:
089: /**
090: * Gets this hash sum as an array of 16 bytes.
091: *
092: * @return Array of 16 bytes, the hash of all updated bytes.
093: *
094: * @since ostermillerutils 1.00.00
095: */
096: public byte[] getHash() {
097: if (!finalState.valid) {
098: finalState.copy(workingState);
099: long bitCount = finalState.bitCount;
100: // Compute the number of left over bits
101: int leftOver = (int) (((bitCount >>> 3)) & 0x3f);
102: // Compute the amount of padding to add based on number of left over bits.
103: int padlen = (leftOver < 56) ? (56 - leftOver)
104: : (120 - leftOver);
105: // add the padding
106: update(finalState, padding, 0, padlen);
107: // add the length (computed before padding was added)
108: update(finalState, encode(bitCount), 0, 8);
109: finalState.valid = true;
110: }
111: // make a copy of the hash before returning it.
112: return encode(finalState.state, 16);
113: }
114:
115: /**
116: * Returns 32-character hex representation of this hash.
117: *
118: * @return String representation of this object's hash.
119: *
120: * @since ostermillerutils 1.00.00
121: */
122: public String getHashString() {
123: return toHex(this .getHash());
124: }
125:
126: /**
127: * Gets the MD5 hash of the given byte array.
128: *
129: * @param b byte array for which an MD5 hash is desired.
130: * @return Array of 16 bytes, the hash of all updated bytes.
131: *
132: * @since ostermillerutils 1.00.00
133: */
134: public static byte[] getHash(byte[] b) {
135: MD5 md5 = new MD5();
136: md5.update(b);
137: return md5.getHash();
138: }
139:
140: /**
141: * Gets the MD5 hash of the given byte array.
142: *
143: * @param b byte array for which an MD5 hash is desired.
144: * @return 32-character hex representation the data's MD5 hash.
145: *
146: * @since ostermillerutils 1.00.00
147: */
148: public static String getHashString(byte[] b) {
149: MD5 md5 = new MD5();
150: md5.update(b);
151: return md5.getHashString();
152: }
153:
154: /**
155: * Gets the MD5 hash the data on the given InputStream.
156: *
157: * @param in byte array for which an MD5 hash is desired.
158: * @return Array of 16 bytes, the hash of all updated bytes.
159: * @throws IOException if an I/O error occurs.
160: *
161: * @since ostermillerutils 1.00.00
162: */
163: public static byte[] getHash(InputStream in) throws IOException {
164: MD5 md5 = new MD5();
165: byte[] buffer = new byte[1024];
166: int read;
167: while ((read = in.read(buffer)) != -1) {
168: md5.update(buffer, read);
169: }
170: return md5.getHash();
171: }
172:
173: /**
174: * Gets the MD5 hash the data on the given InputStream.
175: *
176: * @param in byte array for which an MD5 hash is desired.
177: * @return 32-character hex representation the data's MD5 hash.
178: * @throws IOException if an I/O error occurs.
179: *
180: * @since ostermillerutils 1.00.00
181: */
182: public static String getHashString(InputStream in)
183: throws IOException {
184: MD5 md5 = new MD5();
185: byte[] buffer = new byte[1024];
186: int read;
187: while ((read = in.read(buffer)) != -1) {
188: md5.update(buffer, read);
189: }
190: return md5.getHashString();
191: }
192:
193: /**
194: * Gets the MD5 hash of the given file.
195: *
196: * @param f file for which an MD5 hash is desired.
197: * @return Array of 16 bytes, the hash of all updated bytes.
198: * @throws IOException if an I/O error occurs.
199: *
200: * @since ostermillerutils 1.00.00
201: */
202: public static byte[] getHash(File f) throws IOException {
203: return getHash(new FileInputStream(f));
204: }
205:
206: /**
207: * Gets the MD5 hash of the given file.
208: *
209: * @param f file array for which an MD5 hash is desired.
210: * @return 32-character hex representation the data's MD5 hash.
211: * @throws IOException if an I/O error occurs.
212: *
213: * @since ostermillerutils 1.00.00
214: */
215: public static String getHashString(File f) throws IOException {
216: return getHashString(new FileInputStream(f));
217: }
218:
219: /**
220: * Gets the MD5 hash of the given String.
221: * The string is converted to bytes using the current
222: * platform's default character encoding.
223: *
224: * @param s String for which an MD5 hash is desired.
225: * @return Array of 16 bytes, the hash of all updated bytes.
226: *
227: * @since ostermillerutils 1.00.00
228: */
229: public static byte[] getHash(String s) {
230: MD5 md5 = new MD5();
231: md5.update(s);
232: return md5.getHash();
233: }
234:
235: /**
236: * Gets the MD5 hash of the given String.
237: * The string is converted to bytes using the current
238: * platform's default character encoding.
239: *
240: * @param s String for which an MD5 hash is desired.
241: * @return 32-character hex representation the data's MD5 hash.
242: *
243: * @since ostermillerutils 1.00.00
244: */
245: public static String getHashString(String s) {
246: MD5 md5 = new MD5();
247: md5.update(s);
248: return md5.getHashString();
249: }
250:
251: /**
252: * Gets the MD5 hash of the given String.
253: *
254: * @param s String for which an MD5 hash is desired.
255: * @param enc The name of a supported character encoding.
256: * @return Array of 16 bytes, the hash of all updated bytes.
257: * @throws UnsupportedEncodingException If the named encoding is not supported.
258: *
259: * @since ostermillerutils 1.00.00
260: */
261: public static byte[] getHash(String s, String enc)
262: throws UnsupportedEncodingException {
263: MD5 md5 = new MD5();
264: md5.update(s, enc);
265: return md5.getHash();
266: }
267:
268: /**
269: * Gets the MD5 hash of the given String.
270: *
271: * @param s String for which an MD5 hash is desired.
272: * @param enc The name of a supported character encoding.
273: * @return 32-character hex representation the data's MD5 hash.
274: * @throws UnsupportedEncodingException If the named encoding is not supported.
275: *
276: * @since ostermillerutils 1.00.00
277: */
278: public static String getHashString(String s, String enc)
279: throws UnsupportedEncodingException {
280: MD5 md5 = new MD5();
281: md5.update(s, enc);
282: return md5.getHashString();
283: }
284:
285: /**
286: * Reset the MD5 sum to its initial state.
287: *
288: * @since ostermillerutils 1.00.00
289: */
290: public void reset() {
291: workingState.reset();
292: finalState.valid = false;
293: }
294:
295: /**
296: * Returns 32-character hex representation of this hash.
297: *
298: * @return String representation of this object's hash.
299: *
300: * @since ostermillerutils 1.00.00
301: */
302: public String toString() {
303: return getHashString();
304: }
305:
306: /**
307: * Update this hash with the given data.
308: * <p>
309: * A state may be passed into this method so that we can add padding
310: * and finalize a md5 hash without limiting our ability to update
311: * more data later.
312: * <p>
313: * If length bytes are not available to be hashed, as many bytes as
314: * possible will be hashed.
315: *
316: * @param state Which state is updated.
317: * @param buffer Array of bytes to be hashed.
318: * @param offset Offset to buffer array.
319: * @param length number of bytes to hash.
320: *
321: * @since ostermillerutils 1.00.00
322: */
323: private void update(MD5State state, byte buffer[], int offset,
324: int length) {
325:
326: finalState.valid = false;
327:
328: // if length goes beyond the end of the buffer, cut it short.
329: if ((length + offset) > buffer.length) {
330: length = buffer.length - offset;
331: }
332:
333: // compute number of bytes mod 64
334: // this is what we have sitting in a buffer
335: // that have not been hashed yet
336: int index = (int) (state.bitCount >>> 3) & 0x3f;
337:
338: // add the length to the count (translate bytes to bits)
339: state.bitCount += length << 3;
340:
341: int partlen = 64 - index;
342:
343: int i = 0;
344: if (length >= partlen) {
345: System.arraycopy(buffer, offset, state.buffer, index,
346: partlen);
347: transform(state, decode(state.buffer, 64, 0));
348: for (i = partlen; (i + 63) < length; i += 64) {
349: transform(state, decode(buffer, 64, i));
350: }
351: index = 0;
352: }
353:
354: // buffer remaining input
355: if (i < length) {
356: for (int start = i; i < length; i++) {
357: state.buffer[index + i - start] = buffer[i + offset];
358: }
359: }
360: }
361:
362: /**
363: * Update this hash with the given data.
364: * <p>
365: * If length bytes are not available to be hashed, as many bytes as
366: * possible will be hashed.
367: *
368: * @param buffer Array of bytes to be hashed.
369: * @param offset Offset to buffer array.
370: * @param length number of bytes to hash.
371: *
372: * @since ostermillerutils 1.00.00
373: */
374: public void update(byte buffer[], int offset, int length) {
375: update(workingState, buffer, offset, length);
376: }
377:
378: /**
379: * Update this hash with the given data.
380: * <p>
381: * If length bytes are not available to be hashed, as many bytes as
382: * possible will be hashed.
383: *
384: * @param buffer Array of bytes to be hashed.
385: * @param length number of bytes to hash.
386: *
387: * @since ostermillerutils 1.00.00
388: */
389: public void update(byte buffer[], int length) {
390: update(buffer, 0, length);
391: }
392:
393: /**
394: * Update this hash with the given data.
395: *
396: * @param buffer Array of bytes to be hashed.
397: *
398: * @since ostermillerutils 1.00.00
399: */
400: public void update(byte buffer[]) {
401: update(buffer, 0, buffer.length);
402: }
403:
404: /**
405: * Updates this hash with a single byte.
406: *
407: * @param b byte to be hashed.
408: *
409: * @since ostermillerutils 1.00.00
410: */
411: public void update(byte b) {
412: byte buffer[] = new byte[1];
413: buffer[0] = b;
414: update(buffer, 1);
415: }
416:
417: /**
418: * Update this hash with a long.
419: * This hash will be updated in a little endian order with the
420: * the least significant byte going first.
421: *
422: * @param l long to be hashed.
423: *
424: * @since ostermillerutils 1.00.00
425: */
426: /*
427: private void update (MD5State state, long l) {
428: update(
429: state,
430: new byte[] {
431: (byte)((l >>> 0) & 0xff),
432: (byte)((l >>> 8) & 0xff),
433: (byte)((l >>> 16) & 0xff),
434: (byte)((l >>> 24) & 0xff),
435: (byte)((l >>> 32) & 0xff),
436: (byte)((l >>> 40) & 0xff),
437: (byte)((l >>> 48) & 0xff),
438: (byte)((l >>> 56) & 0xff),
439: },
440: 0,
441: 8
442: );
443: }
444: */
445:
446: /**
447: * Update this hash with a String.
448: * The string is converted to bytes using the current
449: * platform's default character encoding.
450: *
451: * @param s String to be hashed.
452: *
453: * @since ostermillerutils 1.00.00
454: */
455: public void update(String s) {
456: update(s.getBytes());
457: }
458:
459: /**
460: * Update this hash with a String.
461: *
462: * @param s String to be hashed.
463: * @param enc The name of a supported character encoding.
464: * @throws UnsupportedEncodingException If the named encoding is not supported.
465: *
466: * @since ostermillerutils 1.00.00
467: */
468: public void update(String s, String enc)
469: throws UnsupportedEncodingException {
470: update(s.getBytes(enc));
471: }
472:
473: /**
474: * The current state from which the hash sum
475: * can be computed or updated.
476: *
477: * @since ostermillerutils 1.00.00
478: */
479: private MD5State workingState = new MD5State();
480:
481: /**
482: * Cached copy of the final MD5 hash sum. This is created when
483: * the hash is requested and it is invalidated when the hash
484: * is updated.
485: *
486: * @since ostermillerutils 1.00.00
487: */
488: private MD5State finalState = new MD5State();
489:
490: /**
491: * Temporary buffer cached here for performance reasons.
492: *
493: * @since ostermillerutils 1.00.00
494: */
495: private int[] decodeBuffer = new int[16];
496:
497: /**
498: * 64 bytes of padding that can be added if the length
499: * is not divisible by 64.
500: *
501: * @since ostermillerutils 1.00.00
502: */
503: private static final byte padding[] = { (byte) 0x80, 0, 0, 0, 0, 0,
504: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
505: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
506: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };
507:
508: /**
509: * Contains internal state of the MD5 class.
510: * Passes MD5 test suite as defined in RFC1321.
511: *
512: * @since ostermillerutils 1.00.00
513: */
514: private class MD5State {
515:
516: /**
517: * True if this state is valid.
518: *
519: * @since ostermillerutils 1.00.00
520: */
521: public boolean valid = true;
522:
523: /**
524: * Reset to initial state.
525: *
526: * @since ostermillerutils 1.00.00
527: */
528: public void reset() {
529: state[0] = 0x67452301;
530: state[1] = 0xefcdab89;
531: state[2] = 0x98badcfe;
532: state[3] = 0x10325476;
533:
534: bitCount = 0;
535: }
536:
537: /**
538: * 128-byte state
539: *
540: * @since ostermillerutils 1.00.00
541: */
542: public int state[] = new int[4];
543:
544: /**
545: * 64-bit count of the number of bits that have been hashed.
546: *
547: * @since ostermillerutils 1.00.00
548: */
549: public long bitCount;
550:
551: /**
552: * 64-byte buffer (512 bits) for storing to-be-hashed characters
553: *
554: * @since ostermillerutils 1.00.00
555: */
556: public byte buffer[] = new byte[64];
557:
558: public MD5State() {
559: reset();
560: }
561:
562: /**
563: * Set this state to be exactly the same as some other.
564: *
565: * @param from state to copy from.
566: *
567: * @since ostermillerutils 1.00.00
568: */
569: public void copy(MD5State from) {
570: System.arraycopy(from.buffer, 0, this .buffer, 0,
571: this .buffer.length);
572: System.arraycopy(from.state, 0, this .state, 0,
573: this .state.length);
574: this .valid = from.valid;
575: this .bitCount = from.bitCount;
576: }
577:
578: public String toString() {
579: return state[0] + " " + state[1] + " " + state[2] + " "
580: + state[3];
581: }
582: }
583:
584: /**
585: * Turns array of bytes into string representing each byte as
586: * a two digit unsigned hex number.
587: *
588: * @param hash Array of bytes to convert to hex-string
589: * @return Generated hex string
590: *
591: * @since ostermillerutils 1.00.00
592: */
593: private static String toHex(byte hash[]) {
594: String buf = "";
595: for (int i = 0; i < hash.length; i++) {
596: int intVal = hash[i] & 0xff;
597: if (intVal < 0x10) {
598: // append a zero before a one digit hex
599: // number to make it two digits.
600: buf += "0";
601: }
602: buf += (Integer.toHexString(intVal));
603: }
604: return buf.toString();
605: }
606:
607: private static int FF(int a, int b, int c, int d, int x, int s,
608: int ac) {
609: a += ((b & c) | (~b & d));
610: a += x;
611: a += ac;
612: //return rotateLeft(a, s) + b;
613: a = (a << s) | (a >>> (32 - s));
614: return a + b;
615: }
616:
617: private static int GG(int a, int b, int c, int d, int x, int s,
618: int ac) {
619: a += ((b & d) | (c & ~d));
620: a += x;
621: a += ac;
622: //return rotateLeft(a, s) + b;
623: a = (a << s) | (a >>> (32 - s));
624: return a + b;
625: }
626:
627: private static int HH(int a, int b, int c, int d, int x, int s,
628: int ac) {
629: a += (b ^ c ^ d);
630: a += x;
631: a += ac;
632: //return rotateLeft(a, s) + b;
633: a = (a << s) | (a >>> (32 - s));
634: return a + b;
635: }
636:
637: private static int II(int a, int b, int c, int d, int x, int s,
638: int ac) {
639: a += (c ^ (b | ~d));
640: a += x;
641: a += ac;
642: //return rotateLeft(a, s) + b;
643: a = (a << s) | (a >>> (32 - s));
644: return a + b;
645: }
646:
647: private static byte[] encode(long l) {
648: byte[] out = new byte[8];
649: out[0] = (byte) (l & 0xff);
650: out[1] = (byte) ((l >>> 8) & 0xff);
651: out[2] = (byte) ((l >>> 16) & 0xff);
652: out[3] = (byte) ((l >>> 24) & 0xff);
653: out[4] = (byte) ((l >>> 32) & 0xff);
654: out[5] = (byte) ((l >>> 40) & 0xff);
655: out[6] = (byte) ((l >>> 48) & 0xff);
656: out[7] = (byte) ((l >>> 56) & 0xff);
657: return out;
658: }
659:
660: private static byte[] encode(int input[], int len) {
661: byte[] out = new byte[len];
662: int i, j;
663: for (i = j = 0; j < len; i++, j += 4) {
664: out[j] = (byte) (input[i] & 0xff);
665: out[j + 1] = (byte) ((input[i] >>> 8) & 0xff);
666: out[j + 2] = (byte) ((input[i] >>> 16) & 0xff);
667: out[j + 3] = (byte) ((input[i] >>> 24) & 0xff);
668: }
669: return out;
670: }
671:
672: private int[] decode(byte buffer[], int len, int offset) {
673: int i, j;
674: for (i = j = 0; j < len; i++, j += 4) {
675: decodeBuffer[i] = ((int) (buffer[j + offset] & 0xff))
676: | (((int) (buffer[j + 1 + offset] & 0xff)) << 8)
677: | (((int) (buffer[j + 2 + offset] & 0xff)) << 16)
678: | (((int) (buffer[j + 3 + offset] & 0xff)) << 24);
679: }
680: return decodeBuffer;
681: }
682:
683: private static void transform(MD5State state, int[] x) {
684: int a = state.state[0];
685: int b = state.state[1];
686: int c = state.state[2];
687: int d = state.state[3];
688:
689: /* Round 1 */
690: a = FF(a, b, c, d, x[0], 7, 0xd76aa478); /* 1 */
691: d = FF(d, a, b, c, x[1], 12, 0xe8c7b756); /* 2 */
692: c = FF(c, d, a, b, x[2], 17, 0x242070db); /* 3 */
693: b = FF(b, c, d, a, x[3], 22, 0xc1bdceee); /* 4 */
694: a = FF(a, b, c, d, x[4], 7, 0xf57c0faf); /* 5 */
695: d = FF(d, a, b, c, x[5], 12, 0x4787c62a); /* 6 */
696: c = FF(c, d, a, b, x[6], 17, 0xa8304613); /* 7 */
697: b = FF(b, c, d, a, x[7], 22, 0xfd469501); /* 8 */
698: a = FF(a, b, c, d, x[8], 7, 0x698098d8); /* 9 */
699: d = FF(d, a, b, c, x[9], 12, 0x8b44f7af); /* 10 */
700: c = FF(c, d, a, b, x[10], 17, 0xffff5bb1); /* 11 */
701: b = FF(b, c, d, a, x[11], 22, 0x895cd7be); /* 12 */
702: a = FF(a, b, c, d, x[12], 7, 0x6b901122); /* 13 */
703: d = FF(d, a, b, c, x[13], 12, 0xfd987193); /* 14 */
704: c = FF(c, d, a, b, x[14], 17, 0xa679438e); /* 15 */
705: b = FF(b, c, d, a, x[15], 22, 0x49b40821); /* 16 */
706:
707: /* Round 2 */
708: a = GG(a, b, c, d, x[1], 5, 0xf61e2562); /* 17 */
709: d = GG(d, a, b, c, x[6], 9, 0xc040b340); /* 18 */
710: c = GG(c, d, a, b, x[11], 14, 0x265e5a51); /* 19 */
711: b = GG(b, c, d, a, x[0], 20, 0xe9b6c7aa); /* 20 */
712: a = GG(a, b, c, d, x[5], 5, 0xd62f105d); /* 21 */
713: d = GG(d, a, b, c, x[10], 9, 0x02441453); /* 22 */
714: c = GG(c, d, a, b, x[15], 14, 0xd8a1e681); /* 23 */
715: b = GG(b, c, d, a, x[4], 20, 0xe7d3fbc8); /* 24 */
716: a = GG(a, b, c, d, x[9], 5, 0x21e1cde6); /* 25 */
717: d = GG(d, a, b, c, x[14], 9, 0xc33707d6); /* 26 */
718: c = GG(c, d, a, b, x[3], 14, 0xf4d50d87); /* 27 */
719: b = GG(b, c, d, a, x[8], 20, 0x455a14ed); /* 28 */
720: a = GG(a, b, c, d, x[13], 5, 0xa9e3e905); /* 29 */
721: d = GG(d, a, b, c, x[2], 9, 0xfcefa3f8); /* 30 */
722: c = GG(c, d, a, b, x[7], 14, 0x676f02d9); /* 31 */
723: b = GG(b, c, d, a, x[12], 20, 0x8d2a4c8a); /* 32 */
724:
725: /* Round 3 */
726: a = HH(a, b, c, d, x[5], 4, 0xfffa3942); /* 33 */
727: d = HH(d, a, b, c, x[8], 11, 0x8771f681); /* 34 */
728: c = HH(c, d, a, b, x[11], 16, 0x6d9d6122); /* 35 */
729: b = HH(b, c, d, a, x[14], 23, 0xfde5380c); /* 36 */
730: a = HH(a, b, c, d, x[1], 4, 0xa4beea44); /* 37 */
731: d = HH(d, a, b, c, x[4], 11, 0x4bdecfa9); /* 38 */
732: c = HH(c, d, a, b, x[7], 16, 0xf6bb4b60); /* 39 */
733: b = HH(b, c, d, a, x[10], 23, 0xbebfbc70); /* 40 */
734: a = HH(a, b, c, d, x[13], 4, 0x289b7ec6); /* 41 */
735: d = HH(d, a, b, c, x[0], 11, 0xeaa127fa); /* 42 */
736: c = HH(c, d, a, b, x[3], 16, 0xd4ef3085); /* 43 */
737: b = HH(b, c, d, a, x[6], 23, 0x04881d05); /* 44 */
738: a = HH(a, b, c, d, x[9], 4, 0xd9d4d039); /* 45 */
739: d = HH(d, a, b, c, x[12], 11, 0xe6db99e5); /* 46 */
740: c = HH(c, d, a, b, x[15], 16, 0x1fa27cf8); /* 47 */
741: b = HH(b, c, d, a, x[2], 23, 0xc4ac5665); /* 48 */
742:
743: /* Round 4 */
744: a = II(a, b, c, d, x[0], 6, 0xf4292244); /* 49 */
745: d = II(d, a, b, c, x[7], 10, 0x432aff97); /* 50 */
746: c = II(c, d, a, b, x[14], 15, 0xab9423a7); /* 51 */
747: b = II(b, c, d, a, x[5], 21, 0xfc93a039); /* 52 */
748: a = II(a, b, c, d, x[12], 6, 0x655b59c3); /* 53 */
749: d = II(d, a, b, c, x[3], 10, 0x8f0ccc92); /* 54 */
750: c = II(c, d, a, b, x[10], 15, 0xffeff47d); /* 55 */
751: b = II(b, c, d, a, x[1], 21, 0x85845dd1); /* 56 */
752: a = II(a, b, c, d, x[8], 6, 0x6fa87e4f); /* 57 */
753: d = II(d, a, b, c, x[15], 10, 0xfe2ce6e0); /* 58 */
754: c = II(c, d, a, b, x[6], 15, 0xa3014314); /* 59 */
755: b = II(b, c, d, a, x[13], 21, 0x4e0811a1); /* 60 */
756: a = II(a, b, c, d, x[4], 6, 0xf7537e82); /* 61 */
757: d = II(d, a, b, c, x[11], 10, 0xbd3af235); /* 62 */
758: c = II(c, d, a, b, x[2], 15, 0x2ad7d2bb); /* 63 */
759: b = II(b, c, d, a, x[9], 21, 0xeb86d391); /* 64 */
760:
761: state.state[0] += a;
762: state.state[1] += b;
763: state.state[2] += c;
764: state.state[3] += d;
765: }
766: }
|