• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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