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 }