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