1 package org.bouncycastle.crypto.digests;
2 
3 import org.bouncycastle.util.Memoable;
4 import org.bouncycastle.util.Pack;
5 
6 /**
7  * implementation of SHA-1 as outlined in "Handbook of Applied Cryptography", pages 346 - 349.
8  *
9  * It is interesting to ponder why the, apart from the extra IV, the other difference here from MD5
10  * is the "endianness" of the word processing!
11  */
12 public class SHA1Digest
13     extends GeneralDigest
14     implements EncodableDigest
15 {
16     private static final int    DIGEST_LENGTH = 20;
17 
18     private int     H1, H2, H3, H4, H5;
19 
20     private int[]   X = new int[80];
21     private int     xOff;
22 
23     /**
24      * Standard constructor
25      */
SHA1Digest()26     public SHA1Digest()
27     {
28         reset();
29     }
30 
31     /**
32      * Copy constructor.  This will copy the state of the provided
33      * message digest.
34      */
SHA1Digest(SHA1Digest t)35     public SHA1Digest(SHA1Digest t)
36     {
37         super(t);
38 
39         copyIn(t);
40     }
41 
SHA1Digest(byte[] encodedState)42     public SHA1Digest(byte[] encodedState)
43     {
44         super(encodedState);
45 
46         H1 = Pack.bigEndianToInt(encodedState, 16);
47         H2 = Pack.bigEndianToInt(encodedState, 20);
48         H3 = Pack.bigEndianToInt(encodedState, 24);
49         H4 = Pack.bigEndianToInt(encodedState, 28);
50         H5 = Pack.bigEndianToInt(encodedState, 32);
51 
52         xOff = Pack.bigEndianToInt(encodedState, 36);
53         for (int i = 0; i != xOff; i++)
54         {
55             X[i] = Pack.bigEndianToInt(encodedState, 40 + (i * 4));
56         }
57     }
58 
copyIn(SHA1Digest t)59     private void copyIn(SHA1Digest t)
60     {
61         H1 = t.H1;
62         H2 = t.H2;
63         H3 = t.H3;
64         H4 = t.H4;
65         H5 = t.H5;
66 
67         System.arraycopy(t.X, 0, X, 0, t.X.length);
68         xOff = t.xOff;
69     }
70 
getAlgorithmName()71     public String getAlgorithmName()
72     {
73         return "SHA-1";
74     }
75 
getDigestSize()76     public int getDigestSize()
77     {
78         return DIGEST_LENGTH;
79     }
80 
processWord( byte[] in, int inOff)81     protected void processWord(
82         byte[]  in,
83         int     inOff)
84     {
85         // Note: Inlined for performance
86 //        X[xOff] = Pack.bigEndianToInt(in, inOff);
87         int n = in[  inOff] << 24;
88         n |= (in[++inOff] & 0xff) << 16;
89         n |= (in[++inOff] & 0xff) << 8;
90         n |= (in[++inOff] & 0xff);
91         X[xOff] = n;
92 
93         if (++xOff == 16)
94         {
95             processBlock();
96         }
97     }
98 
processLength( long bitLength)99     protected void processLength(
100         long    bitLength)
101     {
102         if (xOff > 14)
103         {
104             processBlock();
105         }
106 
107         X[14] = (int)(bitLength >>> 32);
108         X[15] = (int)(bitLength & 0xffffffff);
109     }
110 
doFinal( byte[] out, int outOff)111     public int doFinal(
112         byte[]  out,
113         int     outOff)
114     {
115         finish();
116 
117         Pack.intToBigEndian(H1, out, outOff);
118         Pack.intToBigEndian(H2, out, outOff + 4);
119         Pack.intToBigEndian(H3, out, outOff + 8);
120         Pack.intToBigEndian(H4, out, outOff + 12);
121         Pack.intToBigEndian(H5, out, outOff + 16);
122 
123         reset();
124 
125         return DIGEST_LENGTH;
126     }
127 
128     /**
129      * reset the chaining variables
130      */
reset()131     public void reset()
132     {
133         super.reset();
134 
135         H1 = 0x67452301;
136         H2 = 0xefcdab89;
137         H3 = 0x98badcfe;
138         H4 = 0x10325476;
139         H5 = 0xc3d2e1f0;
140 
141         xOff = 0;
142         for (int i = 0; i != X.length; i++)
143         {
144             X[i] = 0;
145         }
146     }
147 
148     //
149     // Additive constants
150     //
151     private static final int    Y1 = 0x5a827999;
152     private static final int    Y2 = 0x6ed9eba1;
153     private static final int    Y3 = 0x8f1bbcdc;
154     private static final int    Y4 = 0xca62c1d6;
155 
f( int u, int v, int w)156     private int f(
157         int    u,
158         int    v,
159         int    w)
160     {
161         return ((u & v) | ((~u) & w));
162     }
163 
h( int u, int v, int w)164     private int h(
165         int    u,
166         int    v,
167         int    w)
168     {
169         return (u ^ v ^ w);
170     }
171 
g( int u, int v, int w)172     private int g(
173         int    u,
174         int    v,
175         int    w)
176     {
177         return ((u & v) | (u & w) | (v & w));
178     }
179 
processBlock()180     protected void processBlock()
181     {
182         //
183         // expand 16 word block into 80 word block.
184         //
185         for (int i = 16; i < 80; i++)
186         {
187             int t = X[i - 3] ^ X[i - 8] ^ X[i - 14] ^ X[i - 16];
188             X[i] = t << 1 | t >>> 31;
189         }
190 
191         //
192         // set up working variables.
193         //
194         int     A = H1;
195         int     B = H2;
196         int     C = H3;
197         int     D = H4;
198         int     E = H5;
199 
200         //
201         // round 1
202         //
203         int idx = 0;
204 
205         for (int j = 0; j < 4; j++)
206         {
207             // E = rotateLeft(A, 5) + f(B, C, D) + E + X[idx++] + Y1
208             // B = rotateLeft(B, 30)
209             E += (A << 5 | A >>> 27) + f(B, C, D) + X[idx++] + Y1;
210             B = B << 30 | B >>> 2;
211 
212             D += (E << 5 | E >>> 27) + f(A, B, C) + X[idx++] + Y1;
213             A = A << 30 | A >>> 2;
214 
215             C += (D << 5 | D >>> 27) + f(E, A, B) + X[idx++] + Y1;
216             E = E << 30 | E >>> 2;
217 
218             B += (C << 5 | C >>> 27) + f(D, E, A) + X[idx++] + Y1;
219             D = D << 30 | D >>> 2;
220 
221             A += (B << 5 | B >>> 27) + f(C, D, E) + X[idx++] + Y1;
222             C = C << 30 | C >>> 2;
223         }
224 
225         //
226         // round 2
227         //
228         for (int j = 0; j < 4; j++)
229         {
230             // E = rotateLeft(A, 5) + h(B, C, D) + E + X[idx++] + Y2
231             // B = rotateLeft(B, 30)
232             E += (A << 5 | A >>> 27) + h(B, C, D) + X[idx++] + Y2;
233             B = B << 30 | B >>> 2;
234 
235             D += (E << 5 | E >>> 27) + h(A, B, C) + X[idx++] + Y2;
236             A = A << 30 | A >>> 2;
237 
238             C += (D << 5 | D >>> 27) + h(E, A, B) + X[idx++] + Y2;
239             E = E << 30 | E >>> 2;
240 
241             B += (C << 5 | C >>> 27) + h(D, E, A) + X[idx++] + Y2;
242             D = D << 30 | D >>> 2;
243 
244             A += (B << 5 | B >>> 27) + h(C, D, E) + X[idx++] + Y2;
245             C = C << 30 | C >>> 2;
246         }
247 
248         //
249         // round 3
250         //
251         for (int j = 0; j < 4; j++)
252         {
253             // E = rotateLeft(A, 5) + g(B, C, D) + E + X[idx++] + Y3
254             // B = rotateLeft(B, 30)
255             E += (A << 5 | A >>> 27) + g(B, C, D) + X[idx++] + Y3;
256             B = B << 30 | B >>> 2;
257 
258             D += (E << 5 | E >>> 27) + g(A, B, C) + X[idx++] + Y3;
259             A = A << 30 | A >>> 2;
260 
261             C += (D << 5 | D >>> 27) + g(E, A, B) + X[idx++] + Y3;
262             E = E << 30 | E >>> 2;
263 
264             B += (C << 5 | C >>> 27) + g(D, E, A) + X[idx++] + Y3;
265             D = D << 30 | D >>> 2;
266 
267             A += (B << 5 | B >>> 27) + g(C, D, E) + X[idx++] + Y3;
268             C = C << 30 | C >>> 2;
269         }
270 
271         //
272         // round 4
273         //
274         for (int j = 0; j <= 3; j++)
275         {
276             // E = rotateLeft(A, 5) + h(B, C, D) + E + X[idx++] + Y4
277             // B = rotateLeft(B, 30)
278             E += (A << 5 | A >>> 27) + h(B, C, D) + X[idx++] + Y4;
279             B = B << 30 | B >>> 2;
280 
281             D += (E << 5 | E >>> 27) + h(A, B, C) + X[idx++] + Y4;
282             A = A << 30 | A >>> 2;
283 
284             C += (D << 5 | D >>> 27) + h(E, A, B) + X[idx++] + Y4;
285             E = E << 30 | E >>> 2;
286 
287             B += (C << 5 | C >>> 27) + h(D, E, A) + X[idx++] + Y4;
288             D = D << 30 | D >>> 2;
289 
290             A += (B << 5 | B >>> 27) + h(C, D, E) + X[idx++] + Y4;
291             C = C << 30 | C >>> 2;
292         }
293 
294 
295         H1 += A;
296         H2 += B;
297         H3 += C;
298         H4 += D;
299         H5 += E;
300 
301         //
302         // reset start of the buffer.
303         //
304         xOff = 0;
305         for (int i = 0; i < 16; i++)
306         {
307             X[i] = 0;
308         }
309     }
310 
copy()311     public Memoable copy()
312     {
313         return new SHA1Digest(this);
314     }
315 
reset(Memoable other)316     public void reset(Memoable other)
317     {
318         SHA1Digest d = (SHA1Digest)other;
319 
320         super.copyIn(d);
321         copyIn(d);
322     }
323 
getEncodedState()324     public byte[] getEncodedState()
325     {
326         byte[] state = new byte[40 + xOff * 4];
327 
328         super.populateState(state);
329 
330         Pack.intToBigEndian(H1, state, 16);
331         Pack.intToBigEndian(H2, state, 20);
332         Pack.intToBigEndian(H3, state, 24);
333         Pack.intToBigEndian(H4, state, 28);
334         Pack.intToBigEndian(H5, state, 32);
335         Pack.intToBigEndian(xOff, state, 36);
336 
337         for (int i = 0; i != xOff; i++)
338         {
339             Pack.intToBigEndian(X[i], state, 40 + (i * 4));
340         }
341 
342         return state;
343     }
344 }
345 
346 
347 
348 
349