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