1 package org.bouncycastle.crypto.digests; 2 3 4 import org.bouncycastle.util.Memoable; 5 import org.bouncycastle.util.Pack; 6 7 /** 8 * implementation of MD5 as outlined in "Handbook of Applied Cryptography", pages 346 - 347. 9 */ 10 public class MD5Digest 11 extends GeneralDigest 12 implements EncodableDigest 13 { 14 private static final int DIGEST_LENGTH = 16; 15 16 private int H1, H2, H3, H4; // IV's 17 18 private int[] X = new int[16]; 19 private int xOff; 20 21 /** 22 * Standard constructor 23 */ MD5Digest()24 public MD5Digest() 25 { 26 reset(); 27 } 28 MD5Digest(byte[] encodedState)29 public MD5Digest(byte[] encodedState) 30 { 31 super(encodedState); 32 33 H1 = Pack.bigEndianToInt(encodedState, 16); 34 H2 = Pack.bigEndianToInt(encodedState, 20); 35 H3 = Pack.bigEndianToInt(encodedState, 24); 36 H4 = Pack.bigEndianToInt(encodedState, 28); 37 38 xOff = Pack.bigEndianToInt(encodedState, 32); 39 for (int i = 0; i != xOff; i++) 40 { 41 X[i] = Pack.bigEndianToInt(encodedState, 36 + (i * 4)); 42 } 43 } 44 45 /** 46 * Copy constructor. This will copy the state of the provided 47 * message digest. 48 */ MD5Digest(MD5Digest t)49 public MD5Digest(MD5Digest t) 50 { 51 super(t); 52 53 copyIn(t); 54 } 55 copyIn(MD5Digest t)56 private void copyIn(MD5Digest t) 57 { 58 super.copyIn(t); 59 60 H1 = t.H1; 61 H2 = t.H2; 62 H3 = t.H3; 63 H4 = t.H4; 64 65 System.arraycopy(t.X, 0, X, 0, t.X.length); 66 xOff = t.xOff; 67 } 68 getAlgorithmName()69 public String getAlgorithmName() 70 { 71 return "MD5"; 72 } 73 getDigestSize()74 public int getDigestSize() 75 { 76 return DIGEST_LENGTH; 77 } 78 processWord( byte[] in, int inOff)79 protected void processWord( 80 byte[] in, 81 int inOff) 82 { 83 X[xOff++] = (in[inOff] & 0xff) | ((in[inOff + 1] & 0xff) << 8) 84 | ((in[inOff + 2] & 0xff) << 16) | ((in[inOff + 3] & 0xff) << 24); 85 86 if (xOff == 16) 87 { 88 processBlock(); 89 } 90 } 91 processLength( long bitLength)92 protected void processLength( 93 long bitLength) 94 { 95 if (xOff > 14) 96 { 97 processBlock(); 98 } 99 100 X[14] = (int)(bitLength & 0xffffffff); 101 X[15] = (int)(bitLength >>> 32); 102 } 103 unpackWord( int word, byte[] out, int outOff)104 private void unpackWord( 105 int word, 106 byte[] out, 107 int outOff) 108 { 109 out[outOff] = (byte)word; 110 out[outOff + 1] = (byte)(word >>> 8); 111 out[outOff + 2] = (byte)(word >>> 16); 112 out[outOff + 3] = (byte)(word >>> 24); 113 } 114 doFinal( byte[] out, int outOff)115 public int doFinal( 116 byte[] out, 117 int outOff) 118 { 119 finish(); 120 121 unpackWord(H1, out, outOff); 122 unpackWord(H2, out, outOff + 4); 123 unpackWord(H3, out, outOff + 8); 124 unpackWord(H4, out, outOff + 12); 125 126 reset(); 127 128 return DIGEST_LENGTH; 129 } 130 131 /** 132 * reset the chaining variables to the IV values. 133 */ reset()134 public void reset() 135 { 136 super.reset(); 137 138 H1 = 0x67452301; 139 H2 = 0xefcdab89; 140 H3 = 0x98badcfe; 141 H4 = 0x10325476; 142 143 xOff = 0; 144 145 for (int i = 0; i != X.length; i++) 146 { 147 X[i] = 0; 148 } 149 } 150 151 // 152 // round 1 left rotates 153 // 154 private static final int S11 = 7; 155 private static final int S12 = 12; 156 private static final int S13 = 17; 157 private static final int S14 = 22; 158 159 // 160 // round 2 left rotates 161 // 162 private static final int S21 = 5; 163 private static final int S22 = 9; 164 private static final int S23 = 14; 165 private static final int S24 = 20; 166 167 // 168 // round 3 left rotates 169 // 170 private static final int S31 = 4; 171 private static final int S32 = 11; 172 private static final int S33 = 16; 173 private static final int S34 = 23; 174 175 // 176 // round 4 left rotates 177 // 178 private static final int S41 = 6; 179 private static final int S42 = 10; 180 private static final int S43 = 15; 181 private static final int S44 = 21; 182 183 /* 184 * rotate int x left n bits. 185 */ rotateLeft( int x, int n)186 private int rotateLeft( 187 int x, 188 int n) 189 { 190 return (x << n) | (x >>> (32 - n)); 191 } 192 193 /* 194 * F, G, H and I are the basic MD5 functions. 195 */ F( int u, int v, int w)196 private int F( 197 int u, 198 int v, 199 int w) 200 { 201 return (u & v) | (~u & w); 202 } 203 G( int u, int v, int w)204 private int G( 205 int u, 206 int v, 207 int w) 208 { 209 return (u & w) | (v & ~w); 210 } 211 H( int u, int v, int w)212 private int H( 213 int u, 214 int v, 215 int w) 216 { 217 return u ^ v ^ w; 218 } 219 K( int u, int v, int w)220 private int K( 221 int u, 222 int v, 223 int w) 224 { 225 return v ^ (u | ~w); 226 } 227 processBlock()228 protected void processBlock() 229 { 230 int a = H1; 231 int b = H2; 232 int c = H3; 233 int d = H4; 234 235 // 236 // Round 1 - F cycle, 16 times. 237 // 238 a = rotateLeft(a + F(b, c, d) + X[ 0] + 0xd76aa478, S11) + b; 239 d = rotateLeft(d + F(a, b, c) + X[ 1] + 0xe8c7b756, S12) + a; 240 c = rotateLeft(c + F(d, a, b) + X[ 2] + 0x242070db, S13) + d; 241 b = rotateLeft(b + F(c, d, a) + X[ 3] + 0xc1bdceee, S14) + c; 242 a = rotateLeft(a + F(b, c, d) + X[ 4] + 0xf57c0faf, S11) + b; 243 d = rotateLeft(d + F(a, b, c) + X[ 5] + 0x4787c62a, S12) + a; 244 c = rotateLeft(c + F(d, a, b) + X[ 6] + 0xa8304613, S13) + d; 245 b = rotateLeft(b + F(c, d, a) + X[ 7] + 0xfd469501, S14) + c; 246 a = rotateLeft(a + F(b, c, d) + X[ 8] + 0x698098d8, S11) + b; 247 d = rotateLeft(d + F(a, b, c) + X[ 9] + 0x8b44f7af, S12) + a; 248 c = rotateLeft(c + F(d, a, b) + X[10] + 0xffff5bb1, S13) + d; 249 b = rotateLeft(b + F(c, d, a) + X[11] + 0x895cd7be, S14) + c; 250 a = rotateLeft(a + F(b, c, d) + X[12] + 0x6b901122, S11) + b; 251 d = rotateLeft(d + F(a, b, c) + X[13] + 0xfd987193, S12) + a; 252 c = rotateLeft(c + F(d, a, b) + X[14] + 0xa679438e, S13) + d; 253 b = rotateLeft(b + F(c, d, a) + X[15] + 0x49b40821, S14) + c; 254 255 // 256 // Round 2 - G cycle, 16 times. 257 // 258 a = rotateLeft(a + G(b, c, d) + X[ 1] + 0xf61e2562, S21) + b; 259 d = rotateLeft(d + G(a, b, c) + X[ 6] + 0xc040b340, S22) + a; 260 c = rotateLeft(c + G(d, a, b) + X[11] + 0x265e5a51, S23) + d; 261 b = rotateLeft(b + G(c, d, a) + X[ 0] + 0xe9b6c7aa, S24) + c; 262 a = rotateLeft(a + G(b, c, d) + X[ 5] + 0xd62f105d, S21) + b; 263 d = rotateLeft(d + G(a, b, c) + X[10] + 0x02441453, S22) + a; 264 c = rotateLeft(c + G(d, a, b) + X[15] + 0xd8a1e681, S23) + d; 265 b = rotateLeft(b + G(c, d, a) + X[ 4] + 0xe7d3fbc8, S24) + c; 266 a = rotateLeft(a + G(b, c, d) + X[ 9] + 0x21e1cde6, S21) + b; 267 d = rotateLeft(d + G(a, b, c) + X[14] + 0xc33707d6, S22) + a; 268 c = rotateLeft(c + G(d, a, b) + X[ 3] + 0xf4d50d87, S23) + d; 269 b = rotateLeft(b + G(c, d, a) + X[ 8] + 0x455a14ed, S24) + c; 270 a = rotateLeft(a + G(b, c, d) + X[13] + 0xa9e3e905, S21) + b; 271 d = rotateLeft(d + G(a, b, c) + X[ 2] + 0xfcefa3f8, S22) + a; 272 c = rotateLeft(c + G(d, a, b) + X[ 7] + 0x676f02d9, S23) + d; 273 b = rotateLeft(b + G(c, d, a) + X[12] + 0x8d2a4c8a, S24) + c; 274 275 // 276 // Round 3 - H cycle, 16 times. 277 // 278 a = rotateLeft(a + H(b, c, d) + X[ 5] + 0xfffa3942, S31) + b; 279 d = rotateLeft(d + H(a, b, c) + X[ 8] + 0x8771f681, S32) + a; 280 c = rotateLeft(c + H(d, a, b) + X[11] + 0x6d9d6122, S33) + d; 281 b = rotateLeft(b + H(c, d, a) + X[14] + 0xfde5380c, S34) + c; 282 a = rotateLeft(a + H(b, c, d) + X[ 1] + 0xa4beea44, S31) + b; 283 d = rotateLeft(d + H(a, b, c) + X[ 4] + 0x4bdecfa9, S32) + a; 284 c = rotateLeft(c + H(d, a, b) + X[ 7] + 0xf6bb4b60, S33) + d; 285 b = rotateLeft(b + H(c, d, a) + X[10] + 0xbebfbc70, S34) + c; 286 a = rotateLeft(a + H(b, c, d) + X[13] + 0x289b7ec6, S31) + b; 287 d = rotateLeft(d + H(a, b, c) + X[ 0] + 0xeaa127fa, S32) + a; 288 c = rotateLeft(c + H(d, a, b) + X[ 3] + 0xd4ef3085, S33) + d; 289 b = rotateLeft(b + H(c, d, a) + X[ 6] + 0x04881d05, S34) + c; 290 a = rotateLeft(a + H(b, c, d) + X[ 9] + 0xd9d4d039, S31) + b; 291 d = rotateLeft(d + H(a, b, c) + X[12] + 0xe6db99e5, S32) + a; 292 c = rotateLeft(c + H(d, a, b) + X[15] + 0x1fa27cf8, S33) + d; 293 b = rotateLeft(b + H(c, d, a) + X[ 2] + 0xc4ac5665, S34) + c; 294 295 // 296 // Round 4 - K cycle, 16 times. 297 // 298 a = rotateLeft(a + K(b, c, d) + X[ 0] + 0xf4292244, S41) + b; 299 d = rotateLeft(d + K(a, b, c) + X[ 7] + 0x432aff97, S42) + a; 300 c = rotateLeft(c + K(d, a, b) + X[14] + 0xab9423a7, S43) + d; 301 b = rotateLeft(b + K(c, d, a) + X[ 5] + 0xfc93a039, S44) + c; 302 a = rotateLeft(a + K(b, c, d) + X[12] + 0x655b59c3, S41) + b; 303 d = rotateLeft(d + K(a, b, c) + X[ 3] + 0x8f0ccc92, S42) + a; 304 c = rotateLeft(c + K(d, a, b) + X[10] + 0xffeff47d, S43) + d; 305 b = rotateLeft(b + K(c, d, a) + X[ 1] + 0x85845dd1, S44) + c; 306 a = rotateLeft(a + K(b, c, d) + X[ 8] + 0x6fa87e4f, S41) + b; 307 d = rotateLeft(d + K(a, b, c) + X[15] + 0xfe2ce6e0, S42) + a; 308 c = rotateLeft(c + K(d, a, b) + X[ 6] + 0xa3014314, S43) + d; 309 b = rotateLeft(b + K(c, d, a) + X[13] + 0x4e0811a1, S44) + c; 310 a = rotateLeft(a + K(b, c, d) + X[ 4] + 0xf7537e82, S41) + b; 311 d = rotateLeft(d + K(a, b, c) + X[11] + 0xbd3af235, S42) + a; 312 c = rotateLeft(c + K(d, a, b) + X[ 2] + 0x2ad7d2bb, S43) + d; 313 b = rotateLeft(b + K(c, d, a) + X[ 9] + 0xeb86d391, S44) + c; 314 315 H1 += a; 316 H2 += b; 317 H3 += c; 318 H4 += d; 319 320 // 321 // reset the offset and clean out the word buffer. 322 // 323 xOff = 0; 324 for (int i = 0; i != X.length; i++) 325 { 326 X[i] = 0; 327 } 328 } 329 copy()330 public Memoable copy() 331 { 332 return new MD5Digest(this); 333 } 334 reset(Memoable other)335 public void reset(Memoable other) 336 { 337 MD5Digest d = (MD5Digest)other; 338 339 copyIn(d); 340 } 341 getEncodedState()342 public byte[] getEncodedState() 343 { 344 byte[] state = new byte[36 + xOff * 4]; 345 346 super.populateState(state); 347 348 Pack.intToBigEndian(H1, state, 16); 349 Pack.intToBigEndian(H2, state, 20); 350 Pack.intToBigEndian(H3, state, 24); 351 Pack.intToBigEndian(H4, state, 28); 352 Pack.intToBigEndian(xOff, state, 32); 353 354 for (int i = 0; i != xOff; i++) 355 { 356 Pack.intToBigEndian(X[i], state, 36 + (i * 4)); 357 } 358 359 return state; 360 } 361 } 362