001    /**
002     *  Licensed to the Apache Software Foundation (ASF) under one or more
003     *  contributor license agreements.  See the NOTICE file distributed with
004     *  this work for additional information regarding copyright ownership.
005     *  The ASF licenses this file to You under the Apache License, Version 2.0
006     *  (the "License"); you may not use this file except in compliance with
007     *  the License.  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     *  Unless required by applicable law or agreed to in writing, software
012     *  distributed under the License is distributed on an "AS IS" BASIS,
013     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     *  See the License for the specific language governing permissions and
015     *  limitations under the License.
016     */
017    
018    package org.apache.geronimo.crypto.crypto.digests;
019    
020    
021    /**
022     * implementation of MD5 as outlined in "Handbook of Applied Cryptography", pages 346 - 347.
023     */
024    public class MD5Digest
025        extends GeneralDigest
026    {
027        private static final int    DIGEST_LENGTH = 16;
028    
029        private int     H1, H2, H3, H4;         // IV's
030    
031        private int[]   X = new int[16];
032        private int     xOff;
033    
034        /**
035         * Standard constructor
036         */
037        public MD5Digest()
038        {
039            reset();
040        }
041    
042        /**
043         * Copy constructor.  This will copy the state of the provided
044         * message digest.
045         */
046        public MD5Digest(MD5Digest t)
047        {
048            super(t);
049    
050            H1 = t.H1;
051            H2 = t.H2;
052            H3 = t.H3;
053            H4 = t.H4;
054    
055            System.arraycopy(t.X, 0, X, 0, t.X.length);
056            xOff = t.xOff;
057        }
058    
059        public String getAlgorithmName()
060        {
061            return "MD5";
062        }
063    
064        public int getDigestSize()
065        {
066            return DIGEST_LENGTH;
067        }
068    
069        protected void processWord(
070            byte[]  in,
071            int     inOff)
072        {
073            X[xOff++] = (in[inOff] & 0xff) | ((in[inOff + 1] & 0xff) << 8)
074                | ((in[inOff + 2] & 0xff) << 16) | ((in[inOff + 3] & 0xff) << 24); 
075    
076            if (xOff == 16)
077            {
078                processBlock();
079            }
080        }
081    
082        protected void processLength(
083            long    bitLength)
084        {
085            if (xOff > 14)
086            {
087                processBlock();
088            }
089    
090            X[14] = (int)(bitLength & 0xffffffff);
091            X[15] = (int)(bitLength >>> 32);
092        }
093    
094        private void unpackWord(
095            int     word,
096            byte[]  out,
097            int     outOff)
098        {
099            out[outOff]     = (byte)word;
100            out[outOff + 1] = (byte)(word >>> 8);
101            out[outOff + 2] = (byte)(word >>> 16);
102            out[outOff + 3] = (byte)(word >>> 24);
103        }
104    
105        public int doFinal(
106            byte[]  out,
107            int     outOff)
108        {
109            finish();
110    
111            unpackWord(H1, out, outOff);
112            unpackWord(H2, out, outOff + 4);
113            unpackWord(H3, out, outOff + 8);
114            unpackWord(H4, out, outOff + 12);
115    
116            reset();
117    
118            return DIGEST_LENGTH;
119        }
120    
121        /**
122         * reset the chaining variables to the IV values.
123         */
124        public void reset()
125        {
126            super.reset();
127    
128            H1 = 0x67452301;
129            H2 = 0xefcdab89;
130            H3 = 0x98badcfe;
131            H4 = 0x10325476;
132    
133            xOff = 0;
134    
135            for (int i = 0; i != X.length; i++)
136            {
137                X[i] = 0;
138            }
139        }
140    
141        //
142        // round 1 left rotates
143        //
144        private static final int S11 = 7;
145        private static final int S12 = 12;
146        private static final int S13 = 17;
147        private static final int S14 = 22;
148    
149        //
150        // round 2 left rotates
151        //
152        private static final int S21 = 5;
153        private static final int S22 = 9;
154        private static final int S23 = 14;
155        private static final int S24 = 20;
156    
157        //
158        // round 3 left rotates
159        //
160        private static final int S31 = 4;
161        private static final int S32 = 11;
162        private static final int S33 = 16;
163        private static final int S34 = 23;
164    
165        //
166        // round 4 left rotates
167        //
168        private static final int S41 = 6;
169        private static final int S42 = 10;
170        private static final int S43 = 15;
171        private static final int S44 = 21;
172    
173        /*
174         * rotate int x left n bits.
175         */
176        private int rotateLeft(
177            int x,
178            int n)
179        {
180            return (x << n) | (x >>> (32 - n));
181        }
182    
183        /*
184         * F, G, H and I are the basic MD5 functions.
185         */
186        private int F(
187            int u,
188            int v,
189            int w)
190        {
191            return (u & v) | (~u & w);
192        }
193    
194        private int G(
195            int u,
196            int v,
197            int w)
198        {
199            return (u & w) | (v & ~w);
200        }
201    
202        private int H(
203            int u,
204            int v,
205            int w)
206        {
207            return u ^ v ^ w;
208        }
209    
210        private int K(
211            int u,
212            int v,
213            int w)
214        {
215            return v ^ (u | ~w);
216        }
217    
218        protected void processBlock()
219        {
220            int a = H1;
221            int b = H2;
222            int c = H3;
223            int d = H4;
224    
225            //
226            // Round 1 - F cycle, 16 times.
227            //
228            a = rotateLeft(a + F(b, c, d) + X[ 0] + 0xd76aa478, S11) + b;
229            d = rotateLeft(d + F(a, b, c) + X[ 1] + 0xe8c7b756, S12) + a;
230            c = rotateLeft(c + F(d, a, b) + X[ 2] + 0x242070db, S13) + d;
231            b = rotateLeft(b + F(c, d, a) + X[ 3] + 0xc1bdceee, S14) + c;
232            a = rotateLeft(a + F(b, c, d) + X[ 4] + 0xf57c0faf, S11) + b;
233            d = rotateLeft(d + F(a, b, c) + X[ 5] + 0x4787c62a, S12) + a;
234            c = rotateLeft(c + F(d, a, b) + X[ 6] + 0xa8304613, S13) + d;
235            b = rotateLeft(b + F(c, d, a) + X[ 7] + 0xfd469501, S14) + c;
236            a = rotateLeft(a + F(b, c, d) + X[ 8] + 0x698098d8, S11) + b;
237            d = rotateLeft(d + F(a, b, c) + X[ 9] + 0x8b44f7af, S12) + a;
238            c = rotateLeft(c + F(d, a, b) + X[10] + 0xffff5bb1, S13) + d;
239            b = rotateLeft(b + F(c, d, a) + X[11] + 0x895cd7be, S14) + c;
240            a = rotateLeft(a + F(b, c, d) + X[12] + 0x6b901122, S11) + b;
241            d = rotateLeft(d + F(a, b, c) + X[13] + 0xfd987193, S12) + a;
242            c = rotateLeft(c + F(d, a, b) + X[14] + 0xa679438e, S13) + d;
243            b = rotateLeft(b + F(c, d, a) + X[15] + 0x49b40821, S14) + c;
244    
245            //
246            // Round 2 - G cycle, 16 times.
247            //
248            a = rotateLeft(a + G(b, c, d) + X[ 1] + 0xf61e2562, S21) + b;
249            d = rotateLeft(d + G(a, b, c) + X[ 6] + 0xc040b340, S22) + a;
250            c = rotateLeft(c + G(d, a, b) + X[11] + 0x265e5a51, S23) + d;
251            b = rotateLeft(b + G(c, d, a) + X[ 0] + 0xe9b6c7aa, S24) + c;
252            a = rotateLeft(a + G(b, c, d) + X[ 5] + 0xd62f105d, S21) + b;
253            d = rotateLeft(d + G(a, b, c) + X[10] + 0x02441453, S22) + a;
254            c = rotateLeft(c + G(d, a, b) + X[15] + 0xd8a1e681, S23) + d;
255            b = rotateLeft(b + G(c, d, a) + X[ 4] + 0xe7d3fbc8, S24) + c;
256            a = rotateLeft(a + G(b, c, d) + X[ 9] + 0x21e1cde6, S21) + b;
257            d = rotateLeft(d + G(a, b, c) + X[14] + 0xc33707d6, S22) + a;
258            c = rotateLeft(c + G(d, a, b) + X[ 3] + 0xf4d50d87, S23) + d;
259            b = rotateLeft(b + G(c, d, a) + X[ 8] + 0x455a14ed, S24) + c;
260            a = rotateLeft(a + G(b, c, d) + X[13] + 0xa9e3e905, S21) + b;
261            d = rotateLeft(d + G(a, b, c) + X[ 2] + 0xfcefa3f8, S22) + a;
262            c = rotateLeft(c + G(d, a, b) + X[ 7] + 0x676f02d9, S23) + d;
263            b = rotateLeft(b + G(c, d, a) + X[12] + 0x8d2a4c8a, S24) + c;
264    
265            //
266            // Round 3 - H cycle, 16 times.
267            //
268            a = rotateLeft(a + H(b, c, d) + X[ 5] + 0xfffa3942, S31) + b;
269            d = rotateLeft(d + H(a, b, c) + X[ 8] + 0x8771f681, S32) + a;
270            c = rotateLeft(c + H(d, a, b) + X[11] + 0x6d9d6122, S33) + d;
271            b = rotateLeft(b + H(c, d, a) + X[14] + 0xfde5380c, S34) + c;
272            a = rotateLeft(a + H(b, c, d) + X[ 1] + 0xa4beea44, S31) + b;
273            d = rotateLeft(d + H(a, b, c) + X[ 4] + 0x4bdecfa9, S32) + a;
274            c = rotateLeft(c + H(d, a, b) + X[ 7] + 0xf6bb4b60, S33) + d;
275            b = rotateLeft(b + H(c, d, a) + X[10] + 0xbebfbc70, S34) + c;
276            a = rotateLeft(a + H(b, c, d) + X[13] + 0x289b7ec6, S31) + b;
277            d = rotateLeft(d + H(a, b, c) + X[ 0] + 0xeaa127fa, S32) + a;
278            c = rotateLeft(c + H(d, a, b) + X[ 3] + 0xd4ef3085, S33) + d;
279            b = rotateLeft(b + H(c, d, a) + X[ 6] + 0x04881d05, S34) + c;
280            a = rotateLeft(a + H(b, c, d) + X[ 9] + 0xd9d4d039, S31) + b;
281            d = rotateLeft(d + H(a, b, c) + X[12] + 0xe6db99e5, S32) + a;
282            c = rotateLeft(c + H(d, a, b) + X[15] + 0x1fa27cf8, S33) + d;
283            b = rotateLeft(b + H(c, d, a) + X[ 2] + 0xc4ac5665, S34) + c;
284    
285            //
286            // Round 4 - K cycle, 16 times.
287            //
288            a = rotateLeft(a + K(b, c, d) + X[ 0] + 0xf4292244, S41) + b;
289            d = rotateLeft(d + K(a, b, c) + X[ 7] + 0x432aff97, S42) + a;
290            c = rotateLeft(c + K(d, a, b) + X[14] + 0xab9423a7, S43) + d;
291            b = rotateLeft(b + K(c, d, a) + X[ 5] + 0xfc93a039, S44) + c;
292            a = rotateLeft(a + K(b, c, d) + X[12] + 0x655b59c3, S41) + b;
293            d = rotateLeft(d + K(a, b, c) + X[ 3] + 0x8f0ccc92, S42) + a;
294            c = rotateLeft(c + K(d, a, b) + X[10] + 0xffeff47d, S43) + d;
295            b = rotateLeft(b + K(c, d, a) + X[ 1] + 0x85845dd1, S44) + c;
296            a = rotateLeft(a + K(b, c, d) + X[ 8] + 0x6fa87e4f, S41) + b;
297            d = rotateLeft(d + K(a, b, c) + X[15] + 0xfe2ce6e0, S42) + a;
298            c = rotateLeft(c + K(d, a, b) + X[ 6] + 0xa3014314, S43) + d;
299            b = rotateLeft(b + K(c, d, a) + X[13] + 0x4e0811a1, S44) + c;
300            a = rotateLeft(a + K(b, c, d) + X[ 4] + 0xf7537e82, S41) + b;
301            d = rotateLeft(d + K(a, b, c) + X[11] + 0xbd3af235, S42) + a;
302            c = rotateLeft(c + K(d, a, b) + X[ 2] + 0x2ad7d2bb, S43) + d;
303            b = rotateLeft(b + K(c, d, a) + X[ 9] + 0xeb86d391, S44) + c;
304    
305            H1 += a;
306            H2 += b;
307            H3 += c;
308            H4 += d;
309    
310            //
311            // reset the offset and clean out the word buffer.
312            //
313            xOff = 0;
314            for (int i = 0; i != X.length; i++)
315            {
316                X[i] = 0;
317            }
318        }
319    }