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.util.crypto.digests;
019    
020    
021    /**
022     * implementation of MD4 as RFC 1320 by R. Rivest, MIT Laboratory for
023     * Computer Science and RSA Data Security, Inc.
024     * <p>
025     * <b>NOTE</b>: This algorithm is only included for backwards compatability
026     * with legacy applications, it's not secure, don't use it for anything new!
027     */
028    public class MD4Digest
029        extends GeneralDigest
030    {
031        private static final int    DIGEST_LENGTH = 16;
032    
033        private int     H1, H2, H3, H4;         // IV's
034    
035        private int[]   X = new int[16];
036        private int     xOff;
037    
038        /**
039         * Standard constructor
040         */
041        public MD4Digest()
042        {
043            reset();
044        }
045    
046        /**
047         * Copy constructor.  This will copy the state of the provided
048         * message digest.
049         */
050        public MD4Digest(MD4Digest t)
051        {
052            super(t);
053    
054            H1 = t.H1;
055            H2 = t.H2;
056            H3 = t.H3;
057            H4 = t.H4;
058    
059            System.arraycopy(t.X, 0, X, 0, t.X.length);
060            xOff = t.xOff;
061        }
062    
063        public String getAlgorithmName()
064        {
065            return "MD4";
066        }
067    
068        public int getDigestSize()
069        {
070            return DIGEST_LENGTH;
071        }
072    
073        protected void processWord(
074            byte[]  in,
075            int     inOff)
076        {
077            X[xOff++] = (in[inOff] & 0xff) | ((in[inOff + 1] & 0xff) << 8)
078                | ((in[inOff + 2] & 0xff) << 16) | ((in[inOff + 3] & 0xff) << 24); 
079    
080            if (xOff == 16)
081            {
082                processBlock();
083            }
084        }
085    
086        protected void processLength(
087            long    bitLength)
088        {
089            if (xOff > 14)
090            {
091                processBlock();
092            }
093    
094            X[14] = (int)(bitLength & 0xffffffff);
095            X[15] = (int)(bitLength >>> 32);
096        }
097    
098        private void unpackWord(
099            int     word,
100            byte[]  out,
101            int     outOff)
102        {
103            out[outOff]     = (byte)word;
104            out[outOff + 1] = (byte)(word >>> 8);
105            out[outOff + 2] = (byte)(word >>> 16);
106            out[outOff + 3] = (byte)(word >>> 24);
107        }
108    
109        public int doFinal(
110            byte[]  out,
111            int     outOff)
112        {
113            finish();
114    
115            unpackWord(H1, out, outOff);
116            unpackWord(H2, out, outOff + 4);
117            unpackWord(H3, out, outOff + 8);
118            unpackWord(H4, out, outOff + 12);
119    
120            reset();
121    
122            return DIGEST_LENGTH;
123        }
124    
125        /**
126         * reset the chaining variables to the IV values.
127         */
128        public void reset()
129        {
130            super.reset();
131    
132            H1 = 0x67452301;
133            H2 = 0xefcdab89;
134            H3 = 0x98badcfe;
135            H4 = 0x10325476;
136    
137            xOff = 0;
138    
139            for (int i = 0; i != X.length; i++)
140            {
141                X[i] = 0;
142            }
143        }
144    
145        //
146        // round 1 left rotates
147        //
148        private static final int S11 = 3;
149        private static final int S12 = 7;
150        private static final int S13 = 11;
151        private static final int S14 = 19;
152    
153        //
154        // round 2 left rotates
155        //
156        private static final int S21 = 3;
157        private static final int S22 = 5;
158        private static final int S23 = 9;
159        private static final int S24 = 13;
160    
161        //
162        // round 3 left rotates
163        //
164        private static final int S31 = 3;
165        private static final int S32 = 9;
166        private static final int S33 = 11;
167        private static final int S34 = 15;
168    
169        /*
170         * rotate int x left n bits.
171         */
172        private int rotateLeft(
173            int x,
174            int n)
175        {
176            return (x << n) | (x >>> (32 - n));
177        }
178    
179        /*
180         * F, G, H and I are the basic MD4 functions.
181         */
182        private int F(
183            int u,
184            int v,
185            int w)
186        {
187            return (u & v) | (~u & w);
188        }
189    
190        private int G(
191            int u,
192            int v,
193            int w)
194        {
195            return (u & v) | (u & w) | (v & w);
196        }
197    
198        private int H(
199            int u,
200            int v,
201            int w)
202        {
203            return u ^ v ^ w;
204        }
205    
206        protected void processBlock()
207        {
208            int a = H1;
209            int b = H2;
210            int c = H3;
211            int d = H4;
212    
213            //
214            // Round 1 - F cycle, 16 times.
215            //
216            a = rotateLeft(a + F(b, c, d) + X[ 0], S11);
217            d = rotateLeft(d + F(a, b, c) + X[ 1], S12);
218            c = rotateLeft(c + F(d, a, b) + X[ 2], S13);
219            b = rotateLeft(b + F(c, d, a) + X[ 3], S14);
220            a = rotateLeft(a + F(b, c, d) + X[ 4], S11);
221            d = rotateLeft(d + F(a, b, c) + X[ 5], S12);
222            c = rotateLeft(c + F(d, a, b) + X[ 6], S13);
223            b = rotateLeft(b + F(c, d, a) + X[ 7], S14);
224            a = rotateLeft(a + F(b, c, d) + X[ 8], S11);
225            d = rotateLeft(d + F(a, b, c) + X[ 9], S12);
226            c = rotateLeft(c + F(d, a, b) + X[10], S13);
227            b = rotateLeft(b + F(c, d, a) + X[11], S14);
228            a = rotateLeft(a + F(b, c, d) + X[12], S11);
229            d = rotateLeft(d + F(a, b, c) + X[13], S12);
230            c = rotateLeft(c + F(d, a, b) + X[14], S13);
231            b = rotateLeft(b + F(c, d, a) + X[15], S14);
232    
233            //
234            // Round 2 - G cycle, 16 times.
235            //
236            a = rotateLeft(a + G(b, c, d) + X[ 0] + 0x5a827999, S21);
237            d = rotateLeft(d + G(a, b, c) + X[ 4] + 0x5a827999, S22);
238            c = rotateLeft(c + G(d, a, b) + X[ 8] + 0x5a827999, S23);
239            b = rotateLeft(b + G(c, d, a) + X[12] + 0x5a827999, S24);
240            a = rotateLeft(a + G(b, c, d) + X[ 1] + 0x5a827999, S21);
241            d = rotateLeft(d + G(a, b, c) + X[ 5] + 0x5a827999, S22);
242            c = rotateLeft(c + G(d, a, b) + X[ 9] + 0x5a827999, S23);
243            b = rotateLeft(b + G(c, d, a) + X[13] + 0x5a827999, S24);
244            a = rotateLeft(a + G(b, c, d) + X[ 2] + 0x5a827999, S21);
245            d = rotateLeft(d + G(a, b, c) + X[ 6] + 0x5a827999, S22);
246            c = rotateLeft(c + G(d, a, b) + X[10] + 0x5a827999, S23);
247            b = rotateLeft(b + G(c, d, a) + X[14] + 0x5a827999, S24);
248            a = rotateLeft(a + G(b, c, d) + X[ 3] + 0x5a827999, S21);
249            d = rotateLeft(d + G(a, b, c) + X[ 7] + 0x5a827999, S22);
250            c = rotateLeft(c + G(d, a, b) + X[11] + 0x5a827999, S23);
251            b = rotateLeft(b + G(c, d, a) + X[15] + 0x5a827999, S24);
252    
253            //
254            // Round 3 - H cycle, 16 times.
255            //
256            a = rotateLeft(a + H(b, c, d) + X[ 0] + 0x6ed9eba1, S31);
257            d = rotateLeft(d + H(a, b, c) + X[ 8] + 0x6ed9eba1, S32);
258            c = rotateLeft(c + H(d, a, b) + X[ 4] + 0x6ed9eba1, S33);
259            b = rotateLeft(b + H(c, d, a) + X[12] + 0x6ed9eba1, S34);
260            a = rotateLeft(a + H(b, c, d) + X[ 2] + 0x6ed9eba1, S31);
261            d = rotateLeft(d + H(a, b, c) + X[10] + 0x6ed9eba1, S32);
262            c = rotateLeft(c + H(d, a, b) + X[ 6] + 0x6ed9eba1, S33);
263            b = rotateLeft(b + H(c, d, a) + X[14] + 0x6ed9eba1, S34);
264            a = rotateLeft(a + H(b, c, d) + X[ 1] + 0x6ed9eba1, S31);
265            d = rotateLeft(d + H(a, b, c) + X[ 9] + 0x6ed9eba1, S32);
266            c = rotateLeft(c + H(d, a, b) + X[ 5] + 0x6ed9eba1, S33);
267            b = rotateLeft(b + H(c, d, a) + X[13] + 0x6ed9eba1, S34);
268            a = rotateLeft(a + H(b, c, d) + X[ 3] + 0x6ed9eba1, S31);
269            d = rotateLeft(d + H(a, b, c) + X[11] + 0x6ed9eba1, S32);
270            c = rotateLeft(c + H(d, a, b) + X[ 7] + 0x6ed9eba1, S33);
271            b = rotateLeft(b + H(c, d, a) + X[15] + 0x6ed9eba1, S34);
272    
273            H1 += a;
274            H2 += b;
275            H3 += c;
276            H4 += d;
277    
278            //
279            // reset the offset and clean out the word buffer.
280            //
281            xOff = 0;
282            for (int i = 0; i != X.length; i++)
283            {
284                X[i] = 0;
285            }
286        }
287    }