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 }