001: /*
002: * written Santeri Paavolainen, Helsinki Finland 1996
003: * (c) Santeri Paavolainen, Helsinki Finland 1996
004: * modifications Copyright (C) 2002-2007 Stephen Ostermiller
005: * http://ostermiller.org/contact.pl?regarding=Java+Utilities
006: * Copyright (C) 2007 Stu Thompson stu.comp -at- mailworks.org
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 com.Ostermiller.util;
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 (String element : args) {
078: try {
079: System.out.println(MD5.getHashString(new File(
080: element))
081: + " " + element);
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: InputStream is = new FileInputStream(f);
204: byte[] hash = getHash(is);
205: is.close();
206: return hash;
207: }
208:
209: /**
210: * Gets the MD5 hash of the given file.
211: *
212: * @param f file array for which an MD5 hash is desired.
213: * @return 32-character hex representation the data's MD5 hash.
214: * @throws IOException if an I/O error occurs.
215: *
216: * @since ostermillerutils 1.00.00
217: */
218: public static String getHashString(File f) throws IOException {
219: InputStream is = new FileInputStream(f);
220: String hash = getHashString(is);
221: is.close();
222: return hash;
223: }
224:
225: /**
226: * Gets the MD5 hash of the given String.
227: * The string is converted to bytes using the current
228: * platform's default character encoding.
229: *
230: * @param s String for which an MD5 hash is desired.
231: * @return Array of 16 bytes, the hash of all updated bytes.
232: *
233: * @since ostermillerutils 1.00.00
234: */
235: public static byte[] getHash(String s) {
236: MD5 md5 = new MD5();
237: md5.update(s);
238: return md5.getHash();
239: }
240:
241: /**
242: * Gets the MD5 hash of the given String.
243: * The string is converted to bytes using the current
244: * platform's default character encoding.
245: *
246: * @param s String for which an MD5 hash is desired.
247: * @return 32-character hex representation the data's MD5 hash.
248: *
249: * @since ostermillerutils 1.00.00
250: */
251: public static String getHashString(String s) {
252: MD5 md5 = new MD5();
253: md5.update(s);
254: return md5.getHashString();
255: }
256:
257: /**
258: * Gets the MD5 hash of the given String.
259: *
260: * @param s String for which an MD5 hash is desired.
261: * @param enc The name of a supported character encoding.
262: * @return Array of 16 bytes, the hash of all updated bytes.
263: * @throws UnsupportedEncodingException If the named encoding is not supported.
264: *
265: * @since ostermillerutils 1.00.00
266: */
267: public static byte[] getHash(String s, String enc)
268: throws UnsupportedEncodingException {
269: MD5 md5 = new MD5();
270: md5.update(s, enc);
271: return md5.getHash();
272: }
273:
274: /**
275: * Gets the MD5 hash of the given String.
276: *
277: * @param s String for which an MD5 hash is desired.
278: * @param enc The name of a supported character encoding.
279: * @return 32-character hex representation the data's MD5 hash.
280: * @throws UnsupportedEncodingException If the named encoding is not supported.
281: *
282: * @since ostermillerutils 1.00.00
283: */
284: public static String getHashString(String s, String enc)
285: throws UnsupportedEncodingException {
286: MD5 md5 = new MD5();
287: md5.update(s, enc);
288: return md5.getHashString();
289: }
290:
291: /**
292: * Reset the MD5 sum to its initial state.
293: *
294: * @since ostermillerutils 1.00.00
295: */
296: public void reset() {
297: workingState.reset();
298: finalState.valid = false;
299: }
300:
301: /**
302: * Returns 32-character hex representation of this hash.
303: *
304: * @return String representation of this object's hash.
305: *
306: * @since ostermillerutils 1.00.00
307: */
308: @Override
309: public String toString() {
310: return getHashString();
311: }
312:
313: /**
314: * Update this hash with the given data.
315: * <p>
316: * A state may be passed into this method so that we can add padding
317: * and finalize a md5 hash without limiting our ability to update
318: * more data later.
319: * <p>
320: * If length bytes are not available to be hashed, as many bytes as
321: * possible will be hashed.
322: *
323: * @param state Which state is updated.
324: * @param buffer Array of bytes to be hashed.
325: * @param offset Offset to buffer array.
326: * @param length number of bytes to hash.
327: *
328: * @since ostermillerutils 1.00.00
329: */
330: private void update(MD5State state, byte buffer[], int offset,
331: int length) {
332:
333: finalState.valid = false;
334:
335: // if length goes beyond the end of the buffer, cut it short.
336: if ((length + offset) > buffer.length) {
337: length = buffer.length - offset;
338: }
339:
340: // compute number of bytes mod 64
341: // this is what we have sitting in a buffer
342: // that have not been hashed yet
343: int index = (int) (state.bitCount >>> 3) & 0x3f;
344:
345: // add the length to the count (translate bytes to bits)
346: state.bitCount += length << 3;
347:
348: int partlen = 64 - index;
349:
350: int i = 0;
351: if (length >= partlen) {
352: System.arraycopy(buffer, offset, state.buffer, index,
353: partlen);
354: transform(state, decode(state.buffer, 64, 0));
355: for (i = partlen; (i + 63) < length; i += 64) {
356: transform(state, decode(buffer, 64, i));
357: }
358: index = 0;
359: }
360:
361: // buffer remaining input
362: if (i < length) {
363: for (int start = i; i < length; i++) {
364: state.buffer[index + i - start] = buffer[i + offset];
365: }
366: }
367: }
368:
369: /**
370: * Update this hash with the given data.
371: * <p>
372: * If length bytes are not available to be hashed, as many bytes as
373: * possible will be hashed.
374: *
375: * @param buffer Array of bytes to be hashed.
376: * @param offset Offset to buffer array.
377: * @param length number of bytes to hash.
378: *
379: * @since ostermillerutils 1.00.00
380: */
381: public void update(byte buffer[], int offset, int length) {
382: update(workingState, buffer, offset, length);
383: }
384:
385: /**
386: * Update this hash with the given data.
387: * <p>
388: * If length bytes are not available to be hashed, as many bytes as
389: * possible will be hashed.
390: *
391: * @param buffer Array of bytes to be hashed.
392: * @param length number of bytes to hash.
393: *
394: * @since ostermillerutils 1.00.00
395: */
396: public void update(byte buffer[], int length) {
397: update(buffer, 0, length);
398: }
399:
400: /**
401: * Update this hash with the given data.
402: *
403: * @param buffer Array of bytes to be hashed.
404: *
405: * @since ostermillerutils 1.00.00
406: */
407: public void update(byte buffer[]) {
408: update(buffer, 0, buffer.length);
409: }
410:
411: /**
412: * Updates this hash with a single byte.
413: *
414: * @param b byte to be hashed.
415: *
416: * @since ostermillerutils 1.00.00
417: */
418: public void update(byte b) {
419: byte buffer[] = new byte[1];
420: buffer[0] = b;
421: update(buffer, 1);
422: }
423:
424: /**
425: * Update this hash with a String.
426: * The string is converted to bytes using the current
427: * platform's default character encoding.
428: *
429: * @param s String to be hashed.
430: *
431: * @since ostermillerutils 1.00.00
432: */
433: public void update(String s) {
434: update(s.getBytes());
435: }
436:
437: /**
438: * Update this hash with a String.
439: *
440: * @param s String to be hashed.
441: * @param enc The name of a supported character encoding.
442: * @throws UnsupportedEncodingException If the named encoding is not supported.
443: *
444: * @since ostermillerutils 1.00.00
445: */
446: public void update(String s, String enc)
447: throws UnsupportedEncodingException {
448: update(s.getBytes(enc));
449: }
450:
451: /**
452: * The current state from which the hash sum
453: * can be computed or updated.
454: *
455: * @since ostermillerutils 1.00.00
456: */
457: private MD5State workingState = new MD5State();
458:
459: /**
460: * Cached copy of the final MD5 hash sum. This is created when
461: * the hash is requested and it is invalidated when the hash
462: * is updated.
463: *
464: * @since ostermillerutils 1.00.00
465: */
466: private MD5State finalState = new MD5State();
467:
468: /**
469: * Temporary buffer cached here for performance reasons.
470: *
471: * @since ostermillerutils 1.00.00
472: */
473: private int[] decodeBuffer = new int[16];
474:
475: /**
476: * 64 bytes of padding that can be added if the length
477: * is not divisible by 64.
478: *
479: * @since ostermillerutils 1.00.00
480: */
481: private static final byte padding[] = { (byte) 0x80, 0, 0, 0, 0, 0,
482: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
483: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
484: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };
485:
486: /**
487: * Contains internal state of the MD5 class.
488: * Passes MD5 test suite as defined in RFC1321.
489: *
490: * @since ostermillerutils 1.00.00
491: */
492: private class MD5State {
493:
494: /**
495: * True if this state is valid.
496: *
497: * @since ostermillerutils 1.00.00
498: */
499: private boolean valid = true;
500:
501: /**
502: * Reset to initial state.
503: *
504: * @since ostermillerutils 1.00.00
505: */
506: private void reset() {
507: state[0] = 0x67452301;
508: state[1] = 0xefcdab89;
509: state[2] = 0x98badcfe;
510: state[3] = 0x10325476;
511:
512: bitCount = 0;
513: }
514:
515: /**
516: * 128-byte state
517: *
518: * @since ostermillerutils 1.00.00
519: */
520: private int state[] = new int[4];
521:
522: /**
523: * 64-bit count of the number of bits that have been hashed.
524: *
525: * @since ostermillerutils 1.00.00
526: */
527: private long bitCount;
528:
529: /**
530: * 64-byte buffer (512 bits) for storing to-be-hashed characters
531: *
532: * @since ostermillerutils 1.00.00
533: */
534: private byte buffer[] = new byte[64];
535:
536: private MD5State() {
537: reset();
538: }
539:
540: /**
541: * Set this state to be exactly the same as some other.
542: *
543: * @param from state to copy from.
544: *
545: * @since ostermillerutils 1.00.00
546: */
547: private void copy(MD5State from) {
548: System.arraycopy(from.buffer, 0, this .buffer, 0,
549: this .buffer.length);
550: System.arraycopy(from.state, 0, this .state, 0,
551: this .state.length);
552: this .valid = from.valid;
553: this .bitCount = from.bitCount;
554: }
555: }
556:
557: /**
558: * Turns array of bytes into string representing each byte as
559: * a two digit unsigned hex number.
560: *
561: * @param hash Array of bytes to convert to hex-string
562: * @return Generated hex string
563: *
564: * @since ostermillerutils 1.00.00
565: */
566: private static String toHex(byte hash[]) {
567: StringBuffer buf = new StringBuffer(hash.length * 2);
568: for (byte element : hash) {
569: int intVal = element & 0xff;
570: if (intVal < 0x10) {
571: // append a zero before a one digit hex
572: // number to make it two digits.
573: buf.append("0");
574: }
575: buf.append(Integer.toHexString(intVal));
576: }
577: return buf.toString();
578: }
579:
580: private static int FF(int a, int b, int c, int d, int x, int s,
581: int ac) {
582: a += ((b & c) | (~b & d));
583: a += x;
584: a += ac;
585: //return rotateLeft(a, s) + b;
586: a = (a << s) | (a >>> (32 - s));
587: return a + b;
588: }
589:
590: private static int GG(int a, int b, int c, int d, int x, int s,
591: int ac) {
592: a += ((b & d) | (c & ~d));
593: a += x;
594: a += ac;
595: //return rotateLeft(a, s) + b;
596: a = (a << s) | (a >>> (32 - s));
597: return a + b;
598: }
599:
600: private static int HH(int a, int b, int c, int d, int x, int s,
601: int ac) {
602: a += (b ^ c ^ d);
603: a += x;
604: a += ac;
605: //return rotateLeft(a, s) + b;
606: a = (a << s) | (a >>> (32 - s));
607: return a + b;
608: }
609:
610: private static int II(int a, int b, int c, int d, int x, int s,
611: int ac) {
612: a += (c ^ (b | ~d));
613: a += x;
614: a += ac;
615: //return rotateLeft(a, s) + b;
616: a = (a << s) | (a >>> (32 - s));
617: return a + b;
618: }
619:
620: private static byte[] encode(long l) {
621: byte[] out = new byte[8];
622: out[0] = (byte) (l & 0xff);
623: out[1] = (byte) ((l >>> 8) & 0xff);
624: out[2] = (byte) ((l >>> 16) & 0xff);
625: out[3] = (byte) ((l >>> 24) & 0xff);
626: out[4] = (byte) ((l >>> 32) & 0xff);
627: out[5] = (byte) ((l >>> 40) & 0xff);
628: out[6] = (byte) ((l >>> 48) & 0xff);
629: out[7] = (byte) ((l >>> 56) & 0xff);
630: return out;
631: }
632:
633: private static byte[] encode(int input[], int len) {
634: byte[] out = new byte[len];
635: int i, j;
636: for (i = j = 0; j < len; i++, j += 4) {
637: out[j] = (byte) (input[i] & 0xff);
638: out[j + 1] = (byte) ((input[i] >>> 8) & 0xff);
639: out[j + 2] = (byte) ((input[i] >>> 16) & 0xff);
640: out[j + 3] = (byte) ((input[i] >>> 24) & 0xff);
641: }
642: return out;
643: }
644:
645: private int[] decode(byte buffer[], int len, int offset) {
646: int i, j;
647: for (i = j = 0; j < len; i++, j += 4) {
648: decodeBuffer[i] = ((buffer[j + offset] & 0xff))
649: | (((buffer[j + 1 + offset] & 0xff)) << 8)
650: | (((buffer[j + 2 + offset] & 0xff)) << 16)
651: | (((buffer[j + 3 + offset] & 0xff)) << 24);
652: }
653: return decodeBuffer;
654: }
655:
656: private static void transform(MD5State state, int[] x) {
657: int a = state.state[0];
658: int b = state.state[1];
659: int c = state.state[2];
660: int d = state.state[3];
661:
662: /* Round 1 */
663: a = FF(a, b, c, d, x[0], 7, 0xd76aa478); /* 1 */
664: d = FF(d, a, b, c, x[1], 12, 0xe8c7b756); /* 2 */
665: c = FF(c, d, a, b, x[2], 17, 0x242070db); /* 3 */
666: b = FF(b, c, d, a, x[3], 22, 0xc1bdceee); /* 4 */
667: a = FF(a, b, c, d, x[4], 7, 0xf57c0faf); /* 5 */
668: d = FF(d, a, b, c, x[5], 12, 0x4787c62a); /* 6 */
669: c = FF(c, d, a, b, x[6], 17, 0xa8304613); /* 7 */
670: b = FF(b, c, d, a, x[7], 22, 0xfd469501); /* 8 */
671: a = FF(a, b, c, d, x[8], 7, 0x698098d8); /* 9 */
672: d = FF(d, a, b, c, x[9], 12, 0x8b44f7af); /* 10 */
673: c = FF(c, d, a, b, x[10], 17, 0xffff5bb1); /* 11 */
674: b = FF(b, c, d, a, x[11], 22, 0x895cd7be); /* 12 */
675: a = FF(a, b, c, d, x[12], 7, 0x6b901122); /* 13 */
676: d = FF(d, a, b, c, x[13], 12, 0xfd987193); /* 14 */
677: c = FF(c, d, a, b, x[14], 17, 0xa679438e); /* 15 */
678: b = FF(b, c, d, a, x[15], 22, 0x49b40821); /* 16 */
679:
680: /* Round 2 */
681: a = GG(a, b, c, d, x[1], 5, 0xf61e2562); /* 17 */
682: d = GG(d, a, b, c, x[6], 9, 0xc040b340); /* 18 */
683: c = GG(c, d, a, b, x[11], 14, 0x265e5a51); /* 19 */
684: b = GG(b, c, d, a, x[0], 20, 0xe9b6c7aa); /* 20 */
685: a = GG(a, b, c, d, x[5], 5, 0xd62f105d); /* 21 */
686: d = GG(d, a, b, c, x[10], 9, 0x02441453); /* 22 */
687: c = GG(c, d, a, b, x[15], 14, 0xd8a1e681); /* 23 */
688: b = GG(b, c, d, a, x[4], 20, 0xe7d3fbc8); /* 24 */
689: a = GG(a, b, c, d, x[9], 5, 0x21e1cde6); /* 25 */
690: d = GG(d, a, b, c, x[14], 9, 0xc33707d6); /* 26 */
691: c = GG(c, d, a, b, x[3], 14, 0xf4d50d87); /* 27 */
692: b = GG(b, c, d, a, x[8], 20, 0x455a14ed); /* 28 */
693: a = GG(a, b, c, d, x[13], 5, 0xa9e3e905); /* 29 */
694: d = GG(d, a, b, c, x[2], 9, 0xfcefa3f8); /* 30 */
695: c = GG(c, d, a, b, x[7], 14, 0x676f02d9); /* 31 */
696: b = GG(b, c, d, a, x[12], 20, 0x8d2a4c8a); /* 32 */
697:
698: /* Round 3 */
699: a = HH(a, b, c, d, x[5], 4, 0xfffa3942); /* 33 */
700: d = HH(d, a, b, c, x[8], 11, 0x8771f681); /* 34 */
701: c = HH(c, d, a, b, x[11], 16, 0x6d9d6122); /* 35 */
702: b = HH(b, c, d, a, x[14], 23, 0xfde5380c); /* 36 */
703: a = HH(a, b, c, d, x[1], 4, 0xa4beea44); /* 37 */
704: d = HH(d, a, b, c, x[4], 11, 0x4bdecfa9); /* 38 */
705: c = HH(c, d, a, b, x[7], 16, 0xf6bb4b60); /* 39 */
706: b = HH(b, c, d, a, x[10], 23, 0xbebfbc70); /* 40 */
707: a = HH(a, b, c, d, x[13], 4, 0x289b7ec6); /* 41 */
708: d = HH(d, a, b, c, x[0], 11, 0xeaa127fa); /* 42 */
709: c = HH(c, d, a, b, x[3], 16, 0xd4ef3085); /* 43 */
710: b = HH(b, c, d, a, x[6], 23, 0x04881d05); /* 44 */
711: a = HH(a, b, c, d, x[9], 4, 0xd9d4d039); /* 45 */
712: d = HH(d, a, b, c, x[12], 11, 0xe6db99e5); /* 46 */
713: c = HH(c, d, a, b, x[15], 16, 0x1fa27cf8); /* 47 */
714: b = HH(b, c, d, a, x[2], 23, 0xc4ac5665); /* 48 */
715:
716: /* Round 4 */
717: a = II(a, b, c, d, x[0], 6, 0xf4292244); /* 49 */
718: d = II(d, a, b, c, x[7], 10, 0x432aff97); /* 50 */
719: c = II(c, d, a, b, x[14], 15, 0xab9423a7); /* 51 */
720: b = II(b, c, d, a, x[5], 21, 0xfc93a039); /* 52 */
721: a = II(a, b, c, d, x[12], 6, 0x655b59c3); /* 53 */
722: d = II(d, a, b, c, x[3], 10, 0x8f0ccc92); /* 54 */
723: c = II(c, d, a, b, x[10], 15, 0xffeff47d); /* 55 */
724: b = II(b, c, d, a, x[1], 21, 0x85845dd1); /* 56 */
725: a = II(a, b, c, d, x[8], 6, 0x6fa87e4f); /* 57 */
726: d = II(d, a, b, c, x[15], 10, 0xfe2ce6e0); /* 58 */
727: c = II(c, d, a, b, x[6], 15, 0xa3014314); /* 59 */
728: b = II(b, c, d, a, x[13], 21, 0x4e0811a1); /* 60 */
729: a = II(a, b, c, d, x[4], 6, 0xf7537e82); /* 61 */
730: d = II(d, a, b, c, x[11], 10, 0xbd3af235); /* 62 */
731: c = II(c, d, a, b, x[2], 15, 0x2ad7d2bb); /* 63 */
732: b = II(b, c, d, a, x[9], 21, 0xeb86d391); /* 64 */
733:
734: state.state[0] += a;
735: state.state[1] += b;
736: state.state[2] += c;
737: state.state[3] += d;
738: }
739: }
|