001    package railo.commons.lang;
002    
003    import java.io.ByteArrayInputStream;
004    import java.io.IOException;
005    import java.io.InputStream;
006    
007    
008    /**
009     * class to create a MD5 sum 
010     */
011    public final class Md5 {
012        private static final int BUFFER_SIZE = 1024 ;
013    
014        private static final int S11 = 7 ;
015        private static final int S12 = 12 ;
016        private static final int S13 = 17 ;
017        private static final int S14 = 22 ;
018        private static final int S21 = 5 ;
019        private static final int S22 = 9 ;
020        private static final int S23 = 14 ;
021        private static final int S24 = 20 ;
022        private static final int S31 = 4 ;
023        private static final int S32 = 11 ;
024        private static final int S33 = 16 ;
025        private static final int S34 = 23 ;
026        private static final int S41 = 6 ;
027        private static final int S42 = 10 ;
028        private static final int S43 = 15 ;
029        private static final int S44 = 21 ;
030    
031        private final static byte padding[] = {
032            (byte) 0x80, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0,
033            (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0,
034            (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0,
035            (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, 
036            (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, 
037            (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, 
038            (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, 
039            (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, 
040            (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, 
041            (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, (byte) 0, 
042            (byte) 0, (byte) 0, (byte) 0, (byte) 0
043        } ;
044    
045        private final InputStream in       ;
046        private final int[]         state   ;
047        private long        count    = 0 ;
048        private final byte[]        buffer  ;
049        private byte[]        digest  ;
050     
051        
052        
053        public static String stringify(byte[] digest) {
054                    char[] chars = new char[2*digest.length];
055                    int h;
056                    int l;
057                    int count=0;
058                    for (int i = 0 ; i < digest.length; i++) {
059                        h = (digest[i] & 0xf0) >> 4 ;
060                        l = (digest[i] & 0x0f) ;
061                        chars[count++]= ((char)((h>9) ? 'a'+h-10 : '0'+h));
062                        chars[count++]= ((char)((l>9) ? 'a'+l-10 : '0'+l));
063                    }
064                    return new String(chars) ;
065        }  
066        
067    
068        private final int F(int x, int y, int z) {
069            return ((x & y) | ((~x) & z)) ;
070        }
071    
072        private final int G(int x, int y, int z) {
073            return ((x & z) | (y & (~z))) ;
074        }
075    
076        private final int H(int x, int y, int z) {
077            return (x ^ y ^ z) ;
078        }
079    
080        private final int I(int x, int y, int z) {
081            return (y ^ (x | (~z))) ;
082        }
083    
084        private final int  rotate_left(int x, int n) {
085            return ((x << n) | (x >>> (32-n))) ;
086        }
087    
088        private final int FF(int a,int b,int c,int d,int x,int s,int ac) {
089            a += (F(b, c, d) + x + ac) ;
090            a = rotate_left(a, s) ;
091            a += b ;
092            return a ;
093        }
094    
095        private final int GG(int a,int b,int c,int d,int x,int s,int ac) {
096            a += (G(b, c, d) + x + ac) ;
097            a = rotate_left(a, s) ;
098            a += b ;
099            return a ;
100        }
101    
102        private final int HH(int a,int b,int c,int d,int x,int s,int ac) {
103            a += (H(b, c, d) + x + ac) ;
104            a = rotate_left(a, s) ;
105            a += b ;
106            return a ;
107        }
108    
109        private final int II(int a,int b,int c,int d,int x,int s,int ac) {
110            a += (I(b, c, d) + x + ac) ;
111            a = rotate_left(a, s) ;
112            a += b ;
113            return a;
114        }
115    
116        private final void decode (int output[], byte input[], int off, int len) {
117            int i = 0 ;
118            int j = 0 ;
119            for ( ; j < len; i++, j += 4) {
120                output[i] = ((input[off+j]&0xff)
121                             | ((input[off+j+1] & 0xff) << 8)
122                             | ((input[off+j+2] & 0xff) << 16)
123                             | ((input[off+j+3] & 0xff) << 24)) ;
124            }
125        }
126    
127        private final void transform (byte block[], int offset) {
128            int a   = state[0] ;
129            int b   = state[1] ;
130            int c   = state[2] ;
131            int d   = state[3] ;
132            
133            int x[] = new int[16] ;
134    
135            decode (x, block, offset, 64);
136            /* Round 1 */
137            a = FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
138            d = FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
139            c = FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
140            b = FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
141            a = FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
142            d = FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
143            c = FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
144            b = FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
145            a = FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
146            d = FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
147            c = FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
148            b = FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
149            a = FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
150            d = FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
151            c = FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
152            b = FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
153            /* Round 2 */
154            a = GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
155            d = GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
156            c = GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
157            b = GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
158            a = GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
159            d = GG (d, a, b, c, x[10], S22,  0x2441453); /* 22 */
160            c = GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
161            b = GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
162            a = GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
163            d = GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
164            c = GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
165            b = GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
166            a = GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
167            d = GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
168            c = GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
169            b = GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
170            
171            /* Round 3 */
172            a = HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
173            d = HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
174            c = HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
175            b = HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
176            a = HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
177            d = HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
178            c = HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
179            b = HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
180            a = HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
181            d = HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
182            c = HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
183            b = HH (b, c, d, a, x[ 6], S34,  0x4881d05); /* 44 */
184            a = HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
185            d = HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
186            c = HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
187            b = HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
188            
189            /* Round 4 */
190            a = II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
191            d = II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
192            c = II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
193            b = II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
194            a = II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
195            d = II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
196            c = II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
197            b = II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
198            a = II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
199            d = II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
200            c = II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
201            b = II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
202            a = II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
203            d = II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
204            c = II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
205            b = II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
206    
207            state[0] += a;
208            state[1] += b;
209            state[2] += c;
210            state[3] += d;
211        }
212    
213        private final void update (byte input[], int len) {
214            int index = ((int) (count >> 3)) & 0x3f ;
215            count += (len << 3) ;
216            int partLen = 64 - index ;
217            int i = 0 ;
218            if ( len >= partLen ) {
219                System.arraycopy (input, 0, buffer, index, partLen) ;
220                transform (buffer, 0) ;
221                for (i = partLen ; i + 63 < len ; i+= 64) 
222                    transform (input, i) ;
223                index = 0 ;
224            } else {
225                i = 0 ;
226            }
227            System.arraycopy (input, i, buffer, index, len - i) ;
228        }
229    
230        private byte[] end () {
231                    byte bits[] = new byte[8] ;
232                    for (int i = 0 ; i < 8 ; i++)
233                        bits[i] = (byte) ((count>>>(i*8)) & 0xff) ;
234                    int index  = ((int) (count >> 3)) & 0x3f ;
235                    int padlen = (index < 56) ? (56 - index) : (120 - index) ;
236                    update (padding, padlen) ;
237                    update (bits, 8) ;
238                    return encode(state, 16) ;
239        }
240    
241        // Encode the content.state array into 16 bytes array
242        private byte[] encode (int input[], int len) {
243            byte output[] = new byte[len] ;
244            int i = 0 ;
245            int j = 0 ;
246            for ( ; j < len ; i++, j+= 4) {
247                output[j]   = (byte) ((input[i]      ) & 0xff) ;
248                output[j+1] = (byte) ((input[i] >> 8 ) & 0xff) ;
249                output[j+2] = (byte) ((input[i] >> 16) & 0xff) ;
250                output[j+3] = (byte) ((input[i] >> 24) & 0xff) ;
251            }
252            return output ;
253        }
254    
255        /**
256         * Get the digest for our input stream.
257         * This method constructs the input stream digest, and return it, as a
258         * a String, following the MD5 (rfc1321) algorithm,
259         * @return An instance of String, giving the message digest.
260         * @exception IOException Thrown if the digestifier was unable to read the
261         *    input stream.
262         */
263        private String getDigest () throws IOException {
264            byte buffer[] = new byte[BUFFER_SIZE] ;
265            int  got      = -1 ;
266    
267            if ( digest != null )
268                return stringify(digest) ;
269            while ((got = in.read(buffer)) > 0 ) 
270                update (buffer, got) ;
271            this.digest = end() ;
272            return stringify(digest) ;
273        }
274        
275    
276        
277    
278    
279        /**
280         * Construct a digestifier for the given byte array.
281         * @param input The byte array to be digestified.
282         */
283        private Md5 (byte[] bytes) {
284            
285            this.in      = new ByteArrayInputStream( bytes ) ;
286                    this.state   = new int[4] ;
287                    this.buffer  = new byte[64] ;
288                    this.count   = 0L ;
289                    state[0] = 0x67452301;
290                    state[1] = 0xefcdab89;
291                    state[2] = 0x98badcfe;
292                    state[3] = 0x10325476;
293        }
294        
295    
296        /**
297         * Construct a digestifier for the given string.
298         * @param input The string to be digestified.
299         */
300        private Md5 (String input) {
301            
302            this( input.getBytes() );
303        }    
304      
305        /**
306         * Construct a digestifier for the given input stream.
307         * @param in The input stream to be digestified.
308         */
309        private Md5 (InputStream in) {
310            //this.stringp = false ;
311            this.in      = in ;
312            this.state   = new int[4] ;
313            this.buffer  = new byte[64] ;
314            this.count   = 0 ;
315            state[0] = 0x67452301;
316            state[1] = 0xefcdab89;
317            state[2] = 0x98badcfe;
318            state[3] = 0x10325476;
319        }
320    
321        /**
322         * return md5 from byte array
323         * @param barr byte array to get md5 from
324         * @return md5 from string
325         * @throws IOException
326         */
327        public static String getDigestAsString(byte[] barr) throws IOException {
328            return new Md5(barr).getDigest();
329        }
330        
331        /**
332         * return md5 from string as string
333         * @param str plain string to get md5 from
334         * @return md5 from string
335         * @throws IOException
336         */
337        public static String getDigestAsString(String str) throws IOException {
338            return new Md5 (str).getDigest();
339        }
340        
341        /**
342         * return md5 from InputStream as string
343         * @param in The input stream to be digestified.
344         * @return md5 from string
345         * @throws IOException
346         */
347        public static String getDigestAsString(InputStream in) throws IOException {
348            return new Md5(in).getDigest();
349        }
350    
351    
352    }