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}