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 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 }