View Javadoc
1   package org.bouncycastle.crypto.digests;
2   
3   /*-
4    * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
5    * SNMP Java Client
6    * ჻჻჻჻჻჻
7    * Copyright 2023 MetricsHub, Westhawk
8    * ჻჻჻჻჻჻
9    * This program is free software: you can redistribute it and/or modify
10   * it under the terms of the GNU Lesser General Public License as
11   * published by the Free Software Foundation, either version 3 of the
12   * License, or (at your option) any later version.
13   *
14   * This program is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   * GNU General Lesser Public License for more details.
18   *
19   * You should have received a copy of the GNU General Lesser Public
20   * License along with this program.  If not, see
21   * <http://www.gnu.org/licenses/lgpl-3.0.html>.
22   * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
23   */
24  
25  
26  /**
27   * implementation of MD5 as outlined in "Handbook of Applied Cryptography", pages 346 - 347.
28   */
29  public class MD5Digest
30          extends GeneralDigest {
31      private static final int DIGEST_LENGTH = 16;
32  
33      private int H1, H2, H3, H4; // IV's
34  
35      private int[] X = new int[16];
36      private int xOff;
37  
38      /**
39       * Standard constructor
40       */
41      public MD5Digest() {
42          reset();
43      }
44  
45      /**
46       * Copy constructor. This will copy the state of the provided
47       * message digest.
48       */
49      public MD5Digest(MD5Digest t) {
50          super(t);
51  
52          H1 = t.H1;
53          H2 = t.H2;
54          H3 = t.H3;
55          H4 = t.H4;
56  
57          System.arraycopy(t.X, 0, X, 0, t.X.length);
58          xOff = t.xOff;
59      }
60  
61      public String getAlgorithmName() {
62          return "MD5";
63      }
64  
65      public int getDigestSize() {
66          return DIGEST_LENGTH;
67      }
68  
69      protected void processWord(
70              byte[] in,
71              int inOff) {
72          X[xOff++] = (in[inOff] & 0xff) | ((in[inOff + 1] & 0xff) << 8)
73                  | ((in[inOff + 2] & 0xff) << 16) | ((in[inOff + 3] & 0xff) << 24);
74  
75          if (xOff == 16) {
76              processBlock();
77          }
78      }
79  
80      protected void processLength(
81              long bitLength) {
82          if (xOff > 14) {
83              processBlock();
84          }
85  
86          X[14] = (int) (bitLength & 0xffffffff);
87          X[15] = (int) (bitLength >>> 32);
88      }
89  
90      private void unpackWord(
91              int word,
92              byte[] out,
93              int outOff) {
94          out[outOff] = (byte) word;
95          out[outOff + 1] = (byte) (word >>> 8);
96          out[outOff + 2] = (byte) (word >>> 16);
97          out[outOff + 3] = (byte) (word >>> 24);
98      }
99  
100     public int doFinal(
101             byte[] out,
102             int outOff) {
103         finish();
104 
105         unpackWord(H1, out, outOff);
106         unpackWord(H2, out, outOff + 4);
107         unpackWord(H3, out, outOff + 8);
108         unpackWord(H4, out, outOff + 12);
109 
110         reset();
111 
112         return DIGEST_LENGTH;
113     }
114 
115     /**
116      * reset the chaining variables to the IV values.
117      */
118     public void reset() {
119         super.reset();
120 
121         H1 = 0x67452301;
122         H2 = 0xefcdab89;
123         H3 = 0x98badcfe;
124         H4 = 0x10325476;
125 
126         xOff = 0;
127 
128         for (int i = 0; i != X.length; i++) {
129             X[i] = 0;
130         }
131     }
132 
133     //
134     // round 1 left rotates
135     //
136     private static final int S11 = 7;
137     private static final int S12 = 12;
138     private static final int S13 = 17;
139     private static final int S14 = 22;
140 
141     //
142     // round 2 left rotates
143     //
144     private static final int S21 = 5;
145     private static final int S22 = 9;
146     private static final int S23 = 14;
147     private static final int S24 = 20;
148 
149     //
150     // round 3 left rotates
151     //
152     private static final int S31 = 4;
153     private static final int S32 = 11;
154     private static final int S33 = 16;
155     private static final int S34 = 23;
156 
157     //
158     // round 4 left rotates
159     //
160     private static final int S41 = 6;
161     private static final int S42 = 10;
162     private static final int S43 = 15;
163     private static final int S44 = 21;
164 
165     /*
166      * rotate int x left n bits.
167      */
168     private int rotateLeft(
169             int x,
170             int n) {
171         return (x << n) | (x >>> (32 - n));
172     }
173 
174     /*
175      * F, G, H and I are the basic MD5 functions.
176      */
177     private int F(
178             int u,
179             int v,
180             int w) {
181         return (u & v) | (~u & w);
182     }
183 
184     private int G(
185             int u,
186             int v,
187             int w) {
188         return (u & w) | (v & ~w);
189     }
190 
191     private int H(
192             int u,
193             int v,
194             int w) {
195         return u ^ v ^ w;
196     }
197 
198     private int K(
199             int u,
200             int v,
201             int w) {
202         return v ^ (u | ~w);
203     }
204 
205     protected void processBlock() {
206         int a = H1;
207         int b = H2;
208         int c = H3;
209         int d = H4;
210 
211         //
212         // Round 1 - F cycle, 16 times.
213         //
214         a = rotateLeft((a + F(b, c, d) + X[0] + 0xd76aa478), S11) + b;
215         d = rotateLeft((d + F(a, b, c) + X[1] + 0xe8c7b756), S12) + a;
216         c = rotateLeft((c + F(d, a, b) + X[2] + 0x242070db), S13) + d;
217         b = rotateLeft((b + F(c, d, a) + X[3] + 0xc1bdceee), S14) + c;
218         a = rotateLeft((a + F(b, c, d) + X[4] + 0xf57c0faf), S11) + b;
219         d = rotateLeft((d + F(a, b, c) + X[5] + 0x4787c62a), S12) + a;
220         c = rotateLeft((c + F(d, a, b) + X[6] + 0xa8304613), S13) + d;
221         b = rotateLeft((b + F(c, d, a) + X[7] + 0xfd469501), S14) + c;
222         a = rotateLeft((a + F(b, c, d) + X[8] + 0x698098d8), S11) + b;
223         d = rotateLeft((d + F(a, b, c) + X[9] + 0x8b44f7af), S12) + a;
224         c = rotateLeft((c + F(d, a, b) + X[10] + 0xffff5bb1), S13) + d;
225         b = rotateLeft((b + F(c, d, a) + X[11] + 0x895cd7be), S14) + c;
226         a = rotateLeft((a + F(b, c, d) + X[12] + 0x6b901122), S11) + b;
227         d = rotateLeft((d + F(a, b, c) + X[13] + 0xfd987193), S12) + a;
228         c = rotateLeft((c + F(d, a, b) + X[14] + 0xa679438e), S13) + d;
229         b = rotateLeft((b + F(c, d, a) + X[15] + 0x49b40821), S14) + c;
230 
231         //
232         // Round 2 - G cycle, 16 times.
233         //
234         a = rotateLeft((a + G(b, c, d) + X[1] + 0xf61e2562), S21) + b;
235         d = rotateLeft((d + G(a, b, c) + X[6] + 0xc040b340), S22) + a;
236         c = rotateLeft((c + G(d, a, b) + X[11] + 0x265e5a51), S23) + d;
237         b = rotateLeft((b + G(c, d, a) + X[0] + 0xe9b6c7aa), S24) + c;
238         a = rotateLeft((a + G(b, c, d) + X[5] + 0xd62f105d), S21) + b;
239         d = rotateLeft((d + G(a, b, c) + X[10] + 0x02441453), S22) + a;
240         c = rotateLeft((c + G(d, a, b) + X[15] + 0xd8a1e681), S23) + d;
241         b = rotateLeft((b + G(c, d, a) + X[4] + 0xe7d3fbc8), S24) + c;
242         a = rotateLeft((a + G(b, c, d) + X[9] + 0x21e1cde6), S21) + b;
243         d = rotateLeft((d + G(a, b, c) + X[14] + 0xc33707d6), S22) + a;
244         c = rotateLeft((c + G(d, a, b) + X[3] + 0xf4d50d87), S23) + d;
245         b = rotateLeft((b + G(c, d, a) + X[8] + 0x455a14ed), S24) + c;
246         a = rotateLeft((a + G(b, c, d) + X[13] + 0xa9e3e905), S21) + b;
247         d = rotateLeft((d + G(a, b, c) + X[2] + 0xfcefa3f8), S22) + a;
248         c = rotateLeft((c + G(d, a, b) + X[7] + 0x676f02d9), S23) + d;
249         b = rotateLeft((b + G(c, d, a) + X[12] + 0x8d2a4c8a), S24) + c;
250 
251         //
252         // Round 3 - H cycle, 16 times.
253         //
254         a = rotateLeft((a + H(b, c, d) + X[5] + 0xfffa3942), S31) + b;
255         d = rotateLeft((d + H(a, b, c) + X[8] + 0x8771f681), S32) + a;
256         c = rotateLeft((c + H(d, a, b) + X[11] + 0x6d9d6122), S33) + d;
257         b = rotateLeft((b + H(c, d, a) + X[14] + 0xfde5380c), S34) + c;
258         a = rotateLeft((a + H(b, c, d) + X[1] + 0xa4beea44), S31) + b;
259         d = rotateLeft((d + H(a, b, c) + X[4] + 0x4bdecfa9), S32) + a;
260         c = rotateLeft((c + H(d, a, b) + X[7] + 0xf6bb4b60), S33) + d;
261         b = rotateLeft((b + H(c, d, a) + X[10] + 0xbebfbc70), S34) + c;
262         a = rotateLeft((a + H(b, c, d) + X[13] + 0x289b7ec6), S31) + b;
263         d = rotateLeft((d + H(a, b, c) + X[0] + 0xeaa127fa), S32) + a;
264         c = rotateLeft((c + H(d, a, b) + X[3] + 0xd4ef3085), S33) + d;
265         b = rotateLeft((b + H(c, d, a) + X[6] + 0x04881d05), S34) + c;
266         a = rotateLeft((a + H(b, c, d) + X[9] + 0xd9d4d039), S31) + b;
267         d = rotateLeft((d + H(a, b, c) + X[12] + 0xe6db99e5), S32) + a;
268         c = rotateLeft((c + H(d, a, b) + X[15] + 0x1fa27cf8), S33) + d;
269         b = rotateLeft((b + H(c, d, a) + X[2] + 0xc4ac5665), S34) + c;
270 
271         //
272         // Round 4 - K cycle, 16 times.
273         //
274         a = rotateLeft((a + K(b, c, d) + X[0] + 0xf4292244), S41) + b;
275         d = rotateLeft((d + K(a, b, c) + X[7] + 0x432aff97), S42) + a;
276         c = rotateLeft((c + K(d, a, b) + X[14] + 0xab9423a7), S43) + d;
277         b = rotateLeft((b + K(c, d, a) + X[5] + 0xfc93a039), S44) + c;
278         a = rotateLeft((a + K(b, c, d) + X[12] + 0x655b59c3), S41) + b;
279         d = rotateLeft((d + K(a, b, c) + X[3] + 0x8f0ccc92), S42) + a;
280         c = rotateLeft((c + K(d, a, b) + X[10] + 0xffeff47d), S43) + d;
281         b = rotateLeft((b + K(c, d, a) + X[1] + 0x85845dd1), S44) + c;
282         a = rotateLeft((a + K(b, c, d) + X[8] + 0x6fa87e4f), S41) + b;
283         d = rotateLeft((d + K(a, b, c) + X[15] + 0xfe2ce6e0), S42) + a;
284         c = rotateLeft((c + K(d, a, b) + X[6] + 0xa3014314), S43) + d;
285         b = rotateLeft((b + K(c, d, a) + X[13] + 0x4e0811a1), S44) + c;
286         a = rotateLeft((a + K(b, c, d) + X[4] + 0xf7537e82), S41) + b;
287         d = rotateLeft((d + K(a, b, c) + X[11] + 0xbd3af235), S42) + a;
288         c = rotateLeft((c + K(d, a, b) + X[2] + 0x2ad7d2bb), S43) + d;
289         b = rotateLeft((b + K(c, d, a) + X[9] + 0xeb86d391), S44) + c;
290 
291         H1 += a;
292         H2 += b;
293         H3 += c;
294         H4 += d;
295 
296         //
297         // reset the offset and clean out the word buffer.
298         //
299         xOff = 0;
300         for (int i = 0; i != X.length; i++) {
301             X[i] = 0;
302         }
303     }
304 }