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 * Construct a digestifier for the given string. 279 * @param input The string to be digestified. 280 */ 281 282 private Md5 (String input) { 283 byte bytes[] = new byte[input.length()]; 284 input.getBytes(0, bytes.length, bytes, 0); 285 286 //this.stringp = true ; 287 this.in = new ByteArrayInputStream (bytes) ; 288 this.state = new int[4] ; 289 this.buffer = new byte[64] ; 290 this.count = 0L ; 291 state[0] = 0x67452301; 292 state[1] = 0xefcdab89; 293 state[2] = 0x98badcfe; 294 state[3] = 0x10325476; 295 } 296 297 /** 298 * Construct a digestifier for the given input stream. 299 * @param in The input stream to be digestified. 300 */ 301 private Md5 (InputStream in) { 302 //this.stringp = false ; 303 this.in = in ; 304 this.state = new int[4] ; 305 this.buffer = new byte[64] ; 306 this.count = 0 ; 307 state[0] = 0x67452301; 308 state[1] = 0xefcdab89; 309 state[2] = 0x98badcfe; 310 state[3] = 0x10325476; 311 } 312 313 /** 314 * return md5 from string as string 315 * @param str plain string to get md5 from 316 * @return md5 from string 317 * @throws IOException 318 */ 319 public static String getDigestAsString(String str) throws IOException { 320 return new Md5 (str).getDigest(); 321 } 322 323 /** 324 * return md5 from InputStream as string 325 * @param in The input stream to be digestified. 326 * @return md5 from string 327 * @throws IOException 328 */ 329 public static String getDigestAsString(InputStream in) throws IOException { 330 return new Md5(in).getDigest(); 331 } 332 333 334 }