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