1    package org.bouncycastle.crypto.digests;
2    
3    import org.bouncycastle.crypto.Digest;
4    
5    /**
6     * implementation of SHA-1 as outlined in "Handbook of Applied Cryptography", pages 346 - 349.
7     *
8     * It is interesting to ponder why the, apart from the extra IV, the other difference here from MD5
9     * is the "endienness" of the word processing!
10    */
11   public class SHA1Digest
12       extends GeneralDigest
13   {
14       private static final int    DIGEST_LENGTH = 20;
15   
16       private intintintintintH1H2H3H4 H5;
17   
18       private int[]   X = new int[80];
19       private int     xOff;
20   
21           /**
22            * Standard constructor
23            */
24       public SHA1Digest()
25       {
26           reset();
27       }
28   
29           /**
30            * Copy constructor.  This will copy the state of the provided
31            * message digest.
32            */
33           public SHA1Digest(SHA1Digest t)
34           {
35                   super(t);
36   
37                   H1 = t.H1;
38                   H2 = t.H2;
39                   H3 = t.H3;
40                   H4 = t.H4;
41                   H5 = t.H5;
42   
43                   System.arraycopy(t.X, 0, X, 0, t.X.length);
44                   xOff = t.xOff;
45           }
46   
47       public String getAlgorithmName()
48       {
49           return "SHA-1";
50       }
51   
52       public int getDigestSize()
53       {
54           return DIGEST_LENGTH;
55       }
56   
57       protected void processWord(
58           byte[]  in,
59           int     inOff)
60       {
61           X[xOff++] = ((in[inOff] & 0xff) << 24) | ((in[inOff + 1] & 0xff) << 16)
62                       | ((in[inOff + 2] & 0xff) << 8) | ((in[inOff + 3] & 0xff)); 
63   
64           if (xOff == 16)
65           {
66               processBlock();
67           }
68       }
69   
70       private void unpackWord(
71           int     word,
72           byte[]  out,
73           int     outOff)
74       {
75           out[outOff]     = (byte)(word >>> 24);
76           out[outOff + 1] = (byte)(word >>> 16);
77           out[outOff + 2] = (byte)(word >>> 8);
78           out[outOff + 3] = (byte)word;
79       }
80   
81       protected void processLength(
82           long    bitLength)
83       {
84           if (xOff > 14)
85           {
86               processBlock();
87           }
88   
89           X[14] = (int)(bitLength >>> 32);
90           X[15] = (int)(bitLength & 0xffffffff);
91       }
92   
93       public int doFinal(
94           byte[]  out,
95           int     outOff)
96       {
97           finish();
98   
99           unpackWord(H1, out, outOff);
100          unpackWord(H2, out, outOff + 4);
101          unpackWord(H3, out, outOff + 8);
102          unpackWord(H4, out, outOff + 12);
103          unpackWord(H5, out, outOff + 16);
104  
105          reset();
106  
107          return DIGEST_LENGTH;
108      }
109  
110      /**
111       * reset the chaining variables
112       */
113      public void reset()
114      {
115          super.reset();
116  
117          H1 = 0x67452301;
118          H2 = 0xefcdab89;
119          H3 = 0x98badcfe;
120          H4 = 0x10325476;
121          H5 = 0xc3d2e1f0;
122  
123          xOff = 0;
124          for (int i = 0; i != X.length; i++)
125          {
126              X[i] = 0;
127          }
128      }
129  
130      //
131      // Additive constants
132      //
133      private static final int    Y1 = 0x5a827999;
134      private static final int    Y2 = 0x6ed9eba1;
135      private static final int    Y3 = 0x8f1bbcdc;
136      private static final int    Y4 = 0xca62c1d6;
137  
138      private int f(
139          int    u,
140          int    v,
141          int    w)
142      {
143          return ((u & v) | ((~u) & w));
144      }
145  
146      private int h(
147          int    u,
148          int    v,
149          int    w)
150      {
151          return (u ^ v ^ w);
152      }
153  
154      private int g(
155          int    u,
156          int    v,
157          int    w)
158      {
159          return ((u & v) | (u & w) | (v & w));
160      }
161  
162      private int rotateLeft(
163          int    x,
164          int    n)
165      {
166          return (x << n) | (x >>> (32 - n));
167      }
168  
169      protected void processBlock()
170      {
171          //
172          // expand 16 word block into 80 word block.
173          //
174          for (int i = 16; i <= 79; i++)
175          {
176              X[i] = rotateLeft((X[i - 3] ^ X[i - 8] ^ X[i - 14] ^ X[i - 16]), 1);
177          }
178  
179          //
180          // set up working variables.
181          //
182          int     A = H1;
183          int     B = H2;
184          int     C = H3;
185          int     D = H4;
186          int     E = H5;
187  
188          //
189          // round 1
190          //
191          for (int j = 0; j <= 19; j++)
192          {
193              int     t = rotateLeft(A, 5) + f(B, C, D) + E + X[j] + Y1;
194  
195              E = D;
196              D = C;
197              C = rotateLeft(B, 30);
198              B = A;
199              A = t;
200          }
201  
202          //
203          // round 2
204          //
205          for (int j = 20; j <= 39; j++)
206          {
207              int     t = rotateLeft(A, 5) + h(B, C, D) + E + X[j] + Y2;
208  
209              E = D;
210              D = C;
211              C = rotateLeft(B, 30);
212              B = A;
213              A = t;
214          }
215  
216          //
217          // round 3
218          //
219          for (int j = 40; j <= 59; j++)
220          {
221              int     t = rotateLeft(A, 5) + g(B, C, D) + E + X[j] + Y3;
222  
223              E = D;
224              D = C;
225              C = rotateLeft(B, 30);
226              B = A;
227              A = t;
228          }
229  
230          //
231          // round 4
232          //
233          for (int j = 60; j <= 79; j++)
234          {
235              int     t = rotateLeft(A, 5) + h(B, C, D) + E + X[j] + Y4;
236  
237              E = D;
238              D = C;
239              C = rotateLeft(B, 30);
240              B = A;
241              A = t;
242          }
243  
244          H1 += A;
245          H2 += B;
246          H3 += C;
247          H4 += D;
248          H5 += E;
249  
250          //
251          // reset the offset and clean out the word buffer.
252          //
253          xOff = 0;
254          for (int i = 0; i != X.length; i++)
255          {
256              X[i] = 0;
257          }
258      }
259  }
260