/railo-java/railo-core/src/railo/commons/lang/MD5Hash.java

https://github.com/grapestack/railo · Java · 748 lines · 349 code · 69 blank · 330 comment · 13 complexity · f2e0e26e445b14bfc901d4e2f0f60a16 MD5 · raw file

  1. package railo.commons.lang;
  2. import java.io.File;
  3. import java.io.FileInputStream;
  4. import java.io.IOException;
  5. import java.io.InputStream;
  6. import java.io.UnsupportedEncodingException;
  7. import railo.commons.io.IOUtil;
  8. import railo.commons.io.res.Resource;
  9. public final class MD5Hash {
  10. /**
  11. * Class constructor
  12. *
  13. */
  14. public MD5Hash () {
  15. reset();
  16. }
  17. /**
  18. * Gets this hash sum as an array of 16 bytes.
  19. *
  20. * @return Array of 16 bytes, the hash of all updated bytes.
  21. *
  22. */
  23. public byte[] getHash() {
  24. if (!finalState.valid) {
  25. finalState.copy(workingState);
  26. long bitCount = finalState.bitCount;
  27. // Compute the number of left over bits
  28. int leftOver = (int) (((bitCount >>> 3)) & 0x3f);
  29. // Compute the amount of padding to add based on number of left over bits.
  30. int padlen = (leftOver < 56) ? (56 - leftOver) : (120 - leftOver);
  31. // add the padding
  32. update(finalState, padding, 0, padlen);
  33. // add the length (computed before padding was added)
  34. update(finalState, encode(bitCount), 0, 8);
  35. finalState.valid = true;
  36. }
  37. // make a copy of the hash before returning it.
  38. return encode(finalState.state, 16);
  39. }
  40. /**
  41. * Returns 32-character hex representation of this hash.
  42. *
  43. * @return String representation of this object's hash.
  44. *
  45. *
  46. */
  47. public String getHashString(){
  48. return toHex(this.getHash());
  49. }
  50. /**
  51. * Gets the MD5 hash of the given byte array.
  52. *
  53. * @param b byte array for which an MD5 hash is desired.
  54. * @return Array of 16 bytes, the hash of all updated bytes.
  55. *
  56. *
  57. */
  58. public static byte[] getHash(byte[] b){
  59. MD5Hash md5 = new MD5Hash();
  60. md5.update(b);
  61. return md5.getHash();
  62. }
  63. /**
  64. * Gets the MD5 hash of the given byte array.
  65. *
  66. * @param b byte array for which an MD5 hash is desired.
  67. * @return 32-character hex representation the data's MD5 hash.
  68. *
  69. *
  70. */
  71. public static String getHashString(byte[] b){
  72. MD5Hash md5 = new MD5Hash();
  73. md5.update(b);
  74. return md5.getHashString();
  75. }
  76. /**
  77. * Gets the MD5 hash the data on the given InputStream.
  78. *
  79. * @param in byte array for which an MD5 hash is desired.
  80. * @return Array of 16 bytes, the hash of all updated bytes.
  81. * @throws IOException if an I/O error occurs.
  82. *
  83. *
  84. */
  85. public static byte[] getHash(InputStream in) throws IOException {
  86. MD5Hash md5 = new MD5Hash();
  87. byte[] buffer = new byte[1024];
  88. int read;
  89. while ((read = in.read(buffer)) != -1){
  90. md5.update(buffer, read);
  91. }
  92. return md5.getHash();
  93. }
  94. /**
  95. * Gets the MD5 hash the data on the given InputStream.
  96. *
  97. * @param in byte array for which an MD5 hash is desired.
  98. * @return 32-character hex representation the data's MD5 hash.
  99. * @throws IOException if an I/O error occurs.
  100. *
  101. *
  102. */
  103. public static String getHashString(InputStream in) throws IOException {
  104. MD5Hash md5 = new MD5Hash();
  105. byte[] buffer = new byte[1024];
  106. int read;
  107. while ((read = in.read(buffer)) != -1){
  108. md5.update(buffer, read);
  109. }
  110. return md5.getHashString();
  111. }
  112. /**
  113. * Gets the MD5 hash of the given file.
  114. *
  115. * @param f file for which an MD5 hash is desired.
  116. * @return Array of 16 bytes, the hash of all updated bytes.
  117. * @throws IOException if an I/O error occurs.
  118. *
  119. *
  120. */
  121. public static byte[] getHash(File f) throws IOException {
  122. InputStream is=null;
  123. try {
  124. return getHash(is=new FileInputStream(f));
  125. }
  126. finally {
  127. IOUtil.closeEL(is);
  128. }
  129. }
  130. /**
  131. * Gets the MD5 hash of the given file.
  132. *
  133. * @param f file for which an MD5 hash is desired.
  134. * @return Array of 16 bytes, the hash of all updated bytes.
  135. * @throws IOException if an I/O error occurs.
  136. *
  137. *
  138. */
  139. public static byte[] getHash(Resource f) throws IOException {
  140. InputStream is=null;
  141. try {
  142. return getHash(is=f.getInputStream());
  143. }
  144. finally {
  145. IOUtil.closeEL(is);
  146. }
  147. }
  148. /**
  149. * Gets the MD5 hash of the given file.
  150. *
  151. * @param f file array for which an MD5 hash is desired.
  152. * @return 32-character hex representation the data's MD5 hash.
  153. * @throws IOException if an I/O error occurs.
  154. *
  155. *
  156. */
  157. public static String getHashString(File f) throws IOException {
  158. InputStream is=null;
  159. try {
  160. return getHashString(is=new FileInputStream(f));
  161. }
  162. finally {
  163. IOUtil.closeEL(is);
  164. }
  165. }
  166. /**
  167. * Gets the MD5 hash of the given file.
  168. *
  169. * @param f file array for which an MD5 hash is desired.
  170. * @return 32-character hex representation the data's MD5 hash.
  171. * @throws IOException if an I/O error occurs.
  172. *
  173. *
  174. */
  175. public static String getHashString(Resource f) throws IOException {
  176. InputStream is=null;
  177. try {
  178. return getHashString(is=f.getInputStream());
  179. }
  180. finally {
  181. IOUtil.closeEL(is);
  182. }
  183. }
  184. /**
  185. * Gets the MD5 hash of the given String.
  186. * The string is converted to bytes using the current
  187. * platform's default character encoding.
  188. *
  189. * @param s String for which an MD5 hash is desired.
  190. * @return Array of 16 bytes, the hash of all updated bytes.
  191. *
  192. *
  193. */
  194. public static byte[] getHash(String s){
  195. MD5Hash md5 = new MD5Hash();
  196. md5.update(s);
  197. return md5.getHash();
  198. }
  199. /**
  200. * Gets the MD5 hash of the given String.
  201. * The string is converted to bytes using the current
  202. * platform's default character encoding.
  203. *
  204. * @param s String for which an MD5 hash is desired.
  205. * @return 32-character hex representation the data's MD5 hash.
  206. *
  207. *
  208. */
  209. public static String getHashString(String s){
  210. MD5Hash md5 = new MD5Hash();
  211. md5.update(s);
  212. return md5.getHashString();
  213. }
  214. /**
  215. * Gets the MD5 hash of the given String.
  216. *
  217. * @param s String for which an MD5 hash is desired.
  218. * @param enc The name of a supported character encoding.
  219. * @return Array of 16 bytes, the hash of all updated bytes.
  220. * @throws UnsupportedEncodingException If the named encoding is not supported.
  221. *
  222. *
  223. */
  224. public static byte[] getHash(String s, String enc) throws UnsupportedEncodingException {
  225. MD5Hash md5 = new MD5Hash();
  226. md5.update(s, enc);
  227. return md5.getHash();
  228. }
  229. /**
  230. * Gets the MD5 hash of the given String.
  231. *
  232. * @param s String for which an MD5 hash is desired.
  233. * @param enc The name of a supported character encoding.
  234. * @return 32-character hex representation the data's MD5 hash.
  235. * @throws UnsupportedEncodingException If the named encoding is not supported.
  236. *
  237. *
  238. */
  239. public static String getHashString(String s, String enc) throws UnsupportedEncodingException {
  240. MD5Hash md5 = new MD5Hash();
  241. md5.update(s, enc);
  242. return md5.getHashString();
  243. }
  244. /**
  245. * Reset the MD5 sum to its initial state.
  246. *
  247. *
  248. */
  249. public void reset() {
  250. workingState.reset();
  251. finalState.valid = false;
  252. }
  253. /**
  254. * Returns 32-character hex representation of this hash.
  255. *
  256. * @return String representation of this object's hash.
  257. *
  258. *
  259. */
  260. public String toString(){
  261. return getHashString();
  262. }
  263. /**
  264. * Update this hash with the given data.
  265. * <p>
  266. * A state may be passed into this method so that we can add padding
  267. * and finalize a md5 hash without limiting our ability to update
  268. * more data later.
  269. * <p>
  270. * If length bytes are not available to be hashed, as many bytes as
  271. * possible will be hashed.
  272. *
  273. * @param state Which state is updated.
  274. * @param buffer Array of bytes to be hashed.
  275. * @param offset Offset to buffer array.
  276. * @param length number of bytes to hash.
  277. *
  278. *
  279. */
  280. private void update (MD5State state, byte buffer[], int offset, int length) {
  281. finalState.valid = false;
  282. // if length goes beyond the end of the buffer, cut it short.
  283. if ((length + offset) > buffer.length){
  284. length = buffer.length - offset;
  285. }
  286. // compute number of bytes mod 64
  287. // this is what we have sitting in a buffer
  288. // that have not been hashed yet
  289. int index = (int) (state.bitCount >>> 3) & 0x3f;
  290. // add the length to the count (translate bytes to bits)
  291. state.bitCount += length << 3;
  292. int partlen = 64 - index;
  293. int i = 0;
  294. if (length >= partlen) {
  295. System.arraycopy(buffer, offset, state.buffer, index, partlen);
  296. transform(state, decode(state.buffer, 64, 0));
  297. for (i = partlen; (i + 63) < length; i+= 64){
  298. transform(state, decode(buffer, 64, i));
  299. }
  300. index = 0;
  301. }
  302. // buffer remaining input
  303. if (i < length) {
  304. for (int start = i; i < length; i++) {
  305. state.buffer[index + i - start] = buffer[i + offset];
  306. }
  307. }
  308. }
  309. /**
  310. * Update this hash with the given data.
  311. * <p>
  312. * If length bytes are not available to be hashed, as many bytes as
  313. * possible will be hashed.
  314. *
  315. * @param buffer Array of bytes to be hashed.
  316. * @param offset Offset to buffer array.
  317. * @param length number of bytes to hash.
  318. *
  319. *
  320. */
  321. public void update (byte buffer[], int offset, int length) {
  322. update(workingState, buffer, offset, length);
  323. }
  324. /**
  325. * Update this hash with the given data.
  326. * <p>
  327. * If length bytes are not available to be hashed, as many bytes as
  328. * possible will be hashed.
  329. *
  330. * @param buffer Array of bytes to be hashed.
  331. * @param length number of bytes to hash.
  332. *
  333. *
  334. */
  335. public void update (byte buffer[], int length) {
  336. update(buffer, 0, length);
  337. }
  338. /**
  339. * Update this hash with the given data.
  340. *
  341. * @param buffer Array of bytes to be hashed.
  342. *
  343. *
  344. */
  345. public void update (byte buffer[]) {
  346. update(buffer, 0, buffer.length);
  347. }
  348. /**
  349. * Updates this hash with a single byte.
  350. *
  351. * @param b byte to be hashed.
  352. *
  353. *
  354. */
  355. public void update (byte b) {
  356. byte buffer[] = new byte[1];
  357. buffer[0] = b;
  358. update(buffer, 1);
  359. }
  360. /* *
  361. * Update this hash with a long.
  362. * This hash will be updated in a little endian order with the
  363. * the least significan't byte going first.
  364. *
  365. * @param l long to be hashed.
  366. *
  367. *
  368. * /
  369. private void update (MD5State state, long l) {
  370. update(
  371. state,
  372. new byte[] {
  373. (byte)((l >>> 0) & 0xff),
  374. (byte)((l >>> 8) & 0xff),
  375. (byte)((l >>> 16) & 0xff),
  376. (byte)((l >>> 24) & 0xff),
  377. (byte)((l >>> 32) & 0xff),
  378. (byte)((l >>> 40) & 0xff),
  379. (byte)((l >>> 48) & 0xff),
  380. (byte)((l >>> 56) & 0xff),
  381. },
  382. 0,
  383. 8
  384. );
  385. }*/
  386. /**
  387. * Update this hash with a String.
  388. * The string is converted to bytes using the current
  389. * platform's default character encoding.
  390. *
  391. * @param s String to be hashed.
  392. *
  393. *
  394. */
  395. public void update (String s) {
  396. update(s.getBytes());
  397. }
  398. /**
  399. * Update this hash with a String.
  400. *
  401. * @param s String to be hashed.
  402. * @param enc The name of a supported character encoding.
  403. * @throws UnsupportedEncodingException If the named encoding is not supported.
  404. *
  405. *
  406. */
  407. public void update (String s, String enc) throws UnsupportedEncodingException {
  408. update(s.getBytes(enc));
  409. }
  410. /**
  411. * The current state from which the hash sum
  412. * can be computed or updated.
  413. *
  414. *
  415. */
  416. private MD5State workingState = new MD5State();
  417. /**
  418. * Cached copy of the final MD5 hash sum. This is created when
  419. * the hash is requested and it is invalidated when the hash
  420. * is updated.
  421. *
  422. *
  423. */
  424. private MD5State finalState = new MD5State();
  425. /**
  426. * Temporary buffer cached here for performance reasons.
  427. *
  428. *
  429. */
  430. private int[] decodeBuffer = new int[16];
  431. /**
  432. * 64 bytes of padding that can be added if the length
  433. * is not divisible by 64.
  434. *
  435. *
  436. */
  437. private static final byte padding[] = {
  438. (byte) 0x80, 0, 0, 0, 0, 0, 0, 0,
  439. 0, 0, 0, 0, 0, 0, 0, 0,
  440. 0, 0, 0, 0, 0, 0, 0, 0,
  441. 0, 0, 0, 0, 0, 0, 0, 0,
  442. 0, 0, 0, 0, 0, 0, 0, 0,
  443. 0, 0, 0, 0, 0, 0, 0, 0,
  444. 0, 0, 0, 0, 0, 0, 0, 0,
  445. 0, 0, 0, 0, 0, 0, 0, 0,
  446. };
  447. /**
  448. * Contains internal state of the MD5 class.
  449. * Passes MD5 test suite as defined in RFC1321.
  450. *
  451. *
  452. */
  453. private class MD5State {
  454. /**
  455. * True if this state is valid.
  456. *
  457. *
  458. */
  459. public boolean valid = true;
  460. /**
  461. * Reset to initial state.
  462. *
  463. *
  464. */
  465. public void reset(){
  466. state[0] = 0x67452301;
  467. state[1] = 0xefcdab89;
  468. state[2] = 0x98badcfe;
  469. state[3] = 0x10325476;
  470. bitCount = 0;
  471. }
  472. /**
  473. * 128-byte state
  474. *
  475. *
  476. */
  477. public int state[] = new int[4];
  478. /**
  479. * 64-bit count of the number of bits that have been hashed.
  480. *
  481. *
  482. */
  483. public long bitCount;
  484. /**
  485. * 64-byte buffer (512 bits) for storing to-be-hashed characters
  486. *
  487. *
  488. */
  489. public byte buffer[] = new byte[64];
  490. /**
  491. *
  492. */
  493. public MD5State() {
  494. reset();
  495. }
  496. /**
  497. * Set this state to be exactly the same as some other.
  498. *
  499. * @param from state to copy from.
  500. *
  501. *
  502. */
  503. public void copy(MD5State from) {
  504. System.arraycopy(from.buffer, 0, this.buffer, 0, this.buffer.length);
  505. System.arraycopy(from.state, 0, this.state, 0, this.state.length);
  506. this.valid = from.valid;
  507. this.bitCount = from.bitCount;
  508. }
  509. public String toString(){
  510. return state[0] + " " + state[1] + " " + state[2] + " " + state[3];
  511. }
  512. }
  513. /**
  514. * Turns array of bytes into string representing each byte as
  515. * a two digit unsigned hex number.
  516. *
  517. * @param hash Array of bytes to convert to hex-string
  518. * @return Generated hex string
  519. *
  520. *
  521. */
  522. private String toHex(byte hash[]) {
  523. char[] chars = new char[2*hash.length];
  524. int h;
  525. int l;
  526. int count=0;
  527. for (int i = 0 ; i < hash.length; i++) {
  528. h = (hash[i] & 0xf0) >> 4 ;
  529. l = (hash[i] & 0x0f) ;
  530. chars[count++]= ((char)((h>9) ? 'a'+h-10 : '0'+h));
  531. chars[count++]= ((char)((l>9) ? 'a'+l-10 : '0'+l));
  532. }
  533. return new String(chars) ;
  534. }
  535. private static int FF (int a, int b, int c, int d, int x, int s, int ac) {
  536. a += ((b & c) | (~b & d));
  537. a += x;
  538. a += ac;
  539. //return rotateLeft(a, s) + b;
  540. a = (a << s) | (a >>> (32 - s));
  541. return a + b;
  542. }
  543. private static int GG (int a, int b, int c, int d, int x, int s, int ac) {
  544. a += ((b & d) | (c & ~d));
  545. a += x;
  546. a += ac;
  547. //return rotateLeft(a, s) + b;
  548. a = (a << s) | (a >>> (32 - s));
  549. return a + b;
  550. }
  551. private static int HH (int a, int b, int c, int d, int x, int s, int ac) {
  552. a += (b ^ c ^ d);
  553. a += x;
  554. a += ac;
  555. //return rotateLeft(a, s) + b;
  556. a = (a << s) | (a >>> (32 - s));
  557. return a + b;
  558. }
  559. private static int II (int a, int b, int c, int d, int x, int s, int ac) {
  560. a += (c ^ (b | ~d));
  561. a += x;
  562. a += ac;
  563. //return rotateLeft(a, s) + b;
  564. a = (a << s) | (a >>> (32 - s));
  565. return a + b;
  566. }
  567. private static byte[] encode(long l){
  568. byte[] out = new byte[8];
  569. out[0] = (byte) (l & 0xff);
  570. out[1] = (byte) ((l >>> 8) & 0xff);
  571. out[2] = (byte) ((l >>> 16) & 0xff);
  572. out[3] = (byte) ((l >>> 24) & 0xff);
  573. out[4] = (byte) ((l >>> 32) & 0xff);
  574. out[5] = (byte) ((l >>> 40) & 0xff);
  575. out[6] = (byte) ((l >>> 48) & 0xff);
  576. out[7] = (byte) ((l >>> 56) & 0xff);
  577. return out;
  578. }
  579. private static byte[] encode(int input[], int len){
  580. byte[] out = new byte[len];
  581. int i, j;
  582. for (i = j = 0; j < len; i++, j += 4) {
  583. out[j] = (byte) (input[i] & 0xff);
  584. out[j + 1] = (byte) ((input[i] >>> 8) & 0xff);
  585. out[j + 2] = (byte) ((input[i] >>> 16) & 0xff);
  586. out[j + 3] = (byte) ((input[i] >>> 24) & 0xff);
  587. }
  588. return out;
  589. }
  590. private int[] decode(byte buffer[], int len, int offset){
  591. int i, j=offset;
  592. for (i = 0; j < len; i++,j+=4) {
  593. decodeBuffer[i] = (buffer[j] & 0xff) |
  594. ((buffer[j+1] & 0xff) << 8) |
  595. ((buffer[j+2] & 0xff) << 16) |
  596. ((buffer[j+3] & 0xff) << 24
  597. );
  598. }
  599. return decodeBuffer;
  600. }
  601. private static void transform(MD5State state, int[] x){
  602. int a = state.state[0];
  603. int b = state.state[1];
  604. int c = state.state[2];
  605. int d = state.state[3];
  606. /* Round 1 */
  607. a = FF (a, b, c, d, x[ 0], 7, 0xd76aa478); /* 1 */
  608. d = FF (d, a, b, c, x[ 1], 12, 0xe8c7b756); /* 2 */
  609. c = FF (c, d, a, b, x[ 2], 17, 0x242070db); /* 3 */
  610. b = FF (b, c, d, a, x[ 3], 22, 0xc1bdceee); /* 4 */
  611. a = FF (a, b, c, d, x[ 4], 7, 0xf57c0faf); /* 5 */
  612. d = FF (d, a, b, c, x[ 5], 12, 0x4787c62a); /* 6 */
  613. c = FF (c, d, a, b, x[ 6], 17, 0xa8304613); /* 7 */
  614. b = FF (b, c, d, a, x[ 7], 22, 0xfd469501); /* 8 */
  615. a = FF (a, b, c, d, x[ 8], 7, 0x698098d8); /* 9 */
  616. d = FF (d, a, b, c, x[ 9], 12, 0x8b44f7af); /* 10 */
  617. c = FF (c, d, a, b, x[10], 17, 0xffff5bb1); /* 11 */
  618. b = FF (b, c, d, a, x[11], 22, 0x895cd7be); /* 12 */
  619. a = FF (a, b, c, d, x[12], 7, 0x6b901122); /* 13 */
  620. d = FF (d, a, b, c, x[13], 12, 0xfd987193); /* 14 */
  621. c = FF (c, d, a, b, x[14], 17, 0xa679438e); /* 15 */
  622. b = FF (b, c, d, a, x[15], 22, 0x49b40821); /* 16 */
  623. /* Round 2 */
  624. a = GG (a, b, c, d, x[ 1], 5, 0xf61e2562); /* 17 */
  625. d = GG (d, a, b, c, x[ 6], 9, 0xc040b340); /* 18 */
  626. c = GG (c, d, a, b, x[11], 14, 0x265e5a51); /* 19 */
  627. b = GG (b, c, d, a, x[ 0], 20, 0xe9b6c7aa); /* 20 */
  628. a = GG (a, b, c, d, x[ 5], 5, 0xd62f105d); /* 21 */
  629. d = GG (d, a, b, c, x[10], 9, 0x02441453); /* 22 */
  630. c = GG (c, d, a, b, x[15], 14, 0xd8a1e681); /* 23 */
  631. b = GG (b, c, d, a, x[ 4], 20, 0xe7d3fbc8); /* 24 */
  632. a = GG (a, b, c, d, x[ 9], 5, 0x21e1cde6); /* 25 */
  633. d = GG (d, a, b, c, x[14], 9, 0xc33707d6); /* 26 */
  634. c = GG (c, d, a, b, x[ 3], 14, 0xf4d50d87); /* 27 */
  635. b = GG (b, c, d, a, x[ 8], 20, 0x455a14ed); /* 28 */
  636. a = GG (a, b, c, d, x[13], 5, 0xa9e3e905); /* 29 */
  637. d = GG (d, a, b, c, x[ 2], 9, 0xfcefa3f8); /* 30 */
  638. c = GG (c, d, a, b, x[ 7], 14, 0x676f02d9); /* 31 */
  639. b = GG (b, c, d, a, x[12], 20, 0x8d2a4c8a); /* 32 */
  640. /* Round 3 */
  641. a = HH (a, b, c, d, x[ 5], 4, 0xfffa3942); /* 33 */
  642. d = HH (d, a, b, c, x[ 8], 11, 0x8771f681); /* 34 */
  643. c = HH (c, d, a, b, x[11], 16, 0x6d9d6122); /* 35 */
  644. b = HH (b, c, d, a, x[14], 23, 0xfde5380c); /* 36 */
  645. a = HH (a, b, c, d, x[ 1], 4, 0xa4beea44); /* 37 */
  646. d = HH (d, a, b, c, x[ 4], 11, 0x4bdecfa9); /* 38 */
  647. c = HH (c, d, a, b, x[ 7], 16, 0xf6bb4b60); /* 39 */
  648. b = HH (b, c, d, a, x[10], 23, 0xbebfbc70); /* 40 */
  649. a = HH (a, b, c, d, x[13], 4, 0x289b7ec6); /* 41 */
  650. d = HH (d, a, b, c, x[ 0], 11, 0xeaa127fa); /* 42 */
  651. c = HH (c, d, a, b, x[ 3], 16, 0xd4ef3085); /* 43 */
  652. b = HH (b, c, d, a, x[ 6], 23, 0x04881d05); /* 44 */
  653. a = HH (a, b, c, d, x[ 9], 4, 0xd9d4d039); /* 45 */
  654. d = HH (d, a, b, c, x[12], 11, 0xe6db99e5); /* 46 */
  655. c = HH (c, d, a, b, x[15], 16, 0x1fa27cf8); /* 47 */
  656. b = HH (b, c, d, a, x[ 2], 23, 0xc4ac5665); /* 48 */
  657. /* Round 4 */
  658. a = II (a, b, c, d, x[ 0], 6, 0xf4292244); /* 49 */
  659. d = II (d, a, b, c, x[ 7], 10, 0x432aff97); /* 50 */
  660. c = II (c, d, a, b, x[14], 15, 0xab9423a7); /* 51 */
  661. b = II (b, c, d, a, x[ 5], 21, 0xfc93a039); /* 52 */
  662. a = II (a, b, c, d, x[12], 6, 0x655b59c3); /* 53 */
  663. d = II (d, a, b, c, x[ 3], 10, 0x8f0ccc92); /* 54 */
  664. c = II (c, d, a, b, x[10], 15, 0xffeff47d); /* 55 */
  665. b = II (b, c, d, a, x[ 1], 21, 0x85845dd1); /* 56 */
  666. a = II (a, b, c, d, x[ 8], 6, 0x6fa87e4f); /* 57 */
  667. d = II (d, a, b, c, x[15], 10, 0xfe2ce6e0); /* 58 */
  668. c = II (c, d, a, b, x[ 6], 15, 0xa3014314); /* 59 */
  669. b = II (b, c, d, a, x[13], 21, 0x4e0811a1); /* 60 */
  670. a = II (a, b, c, d, x[ 4], 6, 0xf7537e82); /* 61 */
  671. d = II (d, a, b, c, x[11], 10, 0xbd3af235); /* 62 */
  672. c = II (c, d, a, b, x[ 2], 15, 0x2ad7d2bb); /* 63 */
  673. b = II (b, c, d, a, x[ 9], 21, 0xeb86d391); /* 64 */
  674. state.state[0] += a;
  675. state.state[1] += b;
  676. state.state[2] += c;
  677. state.state[3] += d;
  678. }
  679. }