1package org.bouncycastle.crypto.digests;
2
3
4import org.bouncycastle.crypto.util.Pack;
5import org.bouncycastle.util.Memoable;
6
7
8/**
9 * SHA-224 as described in RFC 3874
10 * <pre>
11 *         block  word  digest
12 * SHA-1   512    32    160
13 * SHA-224 512    32    224
14 * SHA-256 512    32    256
15 * SHA-384 1024   64    384
16 * SHA-512 1024   64    512
17 * </pre>
18 */
19public class SHA224Digest
20    extends GeneralDigest
21{
22    private static final int    DIGEST_LENGTH = 28;
23
24    private int     H1, H2, H3, H4, H5, H6, H7, H8;
25
26    private int[]   X = new int[64];
27    private int     xOff;
28
29    /**
30     * Standard constructor
31     */
32    public SHA224Digest()
33    {
34        reset();
35    }
36
37    /**
38     * Copy constructor.  This will copy the state of the provided
39     * message digest.
40     */
41    public SHA224Digest(SHA224Digest t)
42    {
43        super(t);
44
45        doCopy(t);
46    }
47
48    private void doCopy(SHA224Digest t)
49    {
50        super.copyIn(t);
51
52        H1 = t.H1;
53        H2 = t.H2;
54        H3 = t.H3;
55        H4 = t.H4;
56        H5 = t.H5;
57        H6 = t.H6;
58        H7 = t.H7;
59        H8 = t.H8;
60
61        System.arraycopy(t.X, 0, X, 0, t.X.length);
62        xOff = t.xOff;
63    }
64
65    public String getAlgorithmName()
66    {
67        return "SHA-224";
68    }
69
70    public int getDigestSize()
71    {
72        return DIGEST_LENGTH;
73    }
74
75    protected void processWord(
76        byte[]  in,
77        int     inOff)
78    {
79        // Note: Inlined for performance
80//        X[xOff] = Pack.bigEndianToInt(in, inOff);
81        int n = in[  inOff] << 24;
82        n |= (in[++inOff] & 0xff) << 16;
83        n |= (in[++inOff] & 0xff) << 8;
84        n |= (in[++inOff] & 0xff);
85        X[xOff] = n;
86
87        if (++xOff == 16)
88        {
89            processBlock();
90        }
91    }
92
93    protected void processLength(
94        long    bitLength)
95    {
96        if (xOff > 14)
97        {
98            processBlock();
99        }
100
101        X[14] = (int)(bitLength >>> 32);
102        X[15] = (int)(bitLength & 0xffffffff);
103    }
104
105    public int doFinal(
106        byte[]  out,
107        int     outOff)
108    {
109        finish();
110
111        Pack.intToBigEndian(H1, out, outOff);
112        Pack.intToBigEndian(H2, out, outOff + 4);
113        Pack.intToBigEndian(H3, out, outOff + 8);
114        Pack.intToBigEndian(H4, out, outOff + 12);
115        Pack.intToBigEndian(H5, out, outOff + 16);
116        Pack.intToBigEndian(H6, out, outOff + 20);
117        Pack.intToBigEndian(H7, out, outOff + 24);
118
119        reset();
120
121        return DIGEST_LENGTH;
122    }
123
124    /**
125     * reset the chaining variables
126     */
127    public void reset()
128    {
129        super.reset();
130
131        /* SHA-224 initial hash value
132         */
133
134        H1 = 0xc1059ed8;
135        H2 = 0x367cd507;
136        H3 = 0x3070dd17;
137        H4 = 0xf70e5939;
138        H5 = 0xffc00b31;
139        H6 = 0x68581511;
140        H7 = 0x64f98fa7;
141        H8 = 0xbefa4fa4;
142
143        xOff = 0;
144        for (int i = 0; i != X.length; i++)
145        {
146            X[i] = 0;
147        }
148    }
149
150    protected void processBlock()
151    {
152        //
153        // expand 16 word block into 64 word blocks.
154        //
155        for (int t = 16; t <= 63; t++)
156        {
157            X[t] = Theta1(X[t - 2]) + X[t - 7] + Theta0(X[t - 15]) + X[t - 16];
158        }
159
160        //
161        // set up working variables.
162        //
163        int     a = H1;
164        int     b = H2;
165        int     c = H3;
166        int     d = H4;
167        int     e = H5;
168        int     f = H6;
169        int     g = H7;
170        int     h = H8;
171
172
173        int t = 0;
174        for(int i = 0; i < 8; i ++)
175        {
176            // t = 8 * i
177            h += Sum1(e) + Ch(e, f, g) + K[t] + X[t];
178            d += h;
179            h += Sum0(a) + Maj(a, b, c);
180            ++t;
181
182            // t = 8 * i + 1
183            g += Sum1(d) + Ch(d, e, f) + K[t] + X[t];
184            c += g;
185            g += Sum0(h) + Maj(h, a, b);
186            ++t;
187
188            // t = 8 * i + 2
189            f += Sum1(c) + Ch(c, d, e) + K[t] + X[t];
190            b += f;
191            f += Sum0(g) + Maj(g, h, a);
192            ++t;
193
194            // t = 8 * i + 3
195            e += Sum1(b) + Ch(b, c, d) + K[t] + X[t];
196            a += e;
197            e += Sum0(f) + Maj(f, g, h);
198            ++t;
199
200            // t = 8 * i + 4
201            d += Sum1(a) + Ch(a, b, c) + K[t] + X[t];
202            h += d;
203            d += Sum0(e) + Maj(e, f, g);
204            ++t;
205
206            // t = 8 * i + 5
207            c += Sum1(h) + Ch(h, a, b) + K[t] + X[t];
208            g += c;
209            c += Sum0(d) + Maj(d, e, f);
210            ++t;
211
212            // t = 8 * i + 6
213            b += Sum1(g) + Ch(g, h, a) + K[t] + X[t];
214            f += b;
215            b += Sum0(c) + Maj(c, d, e);
216            ++t;
217
218            // t = 8 * i + 7
219            a += Sum1(f) + Ch(f, g, h) + K[t] + X[t];
220            e += a;
221            a += Sum0(b) + Maj(b, c, d);
222            ++t;
223        }
224
225        H1 += a;
226        H2 += b;
227        H3 += c;
228        H4 += d;
229        H5 += e;
230        H6 += f;
231        H7 += g;
232        H8 += h;
233
234        //
235        // reset the offset and clean out the word buffer.
236        //
237        xOff = 0;
238        for (int i = 0; i < 16; i++)
239        {
240            X[i] = 0;
241        }
242    }
243
244    /* SHA-224 functions */
245    private int Ch(
246        int    x,
247        int    y,
248        int    z)
249    {
250        return ((x & y) ^ ((~x) & z));
251    }
252
253    private int Maj(
254        int    x,
255        int    y,
256        int    z)
257    {
258        return ((x & y) ^ (x & z) ^ (y & z));
259    }
260
261    private int Sum0(
262        int    x)
263    {
264        return ((x >>> 2) | (x << 30)) ^ ((x >>> 13) | (x << 19)) ^ ((x >>> 22) | (x << 10));
265    }
266
267    private int Sum1(
268        int    x)
269    {
270        return ((x >>> 6) | (x << 26)) ^ ((x >>> 11) | (x << 21)) ^ ((x >>> 25) | (x << 7));
271    }
272
273    private int Theta0(
274        int    x)
275    {
276        return ((x >>> 7) | (x << 25)) ^ ((x >>> 18) | (x << 14)) ^ (x >>> 3);
277    }
278
279    private int Theta1(
280        int    x)
281    {
282        return ((x >>> 17) | (x << 15)) ^ ((x >>> 19) | (x << 13)) ^ (x >>> 10);
283    }
284
285    /* SHA-224 Constants
286     * (represent the first 32 bits of the fractional parts of the
287     * cube roots of the first sixty-four prime numbers)
288     */
289    static final int K[] = {
290        0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
291        0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
292        0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
293        0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
294        0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
295        0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
296        0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
297    };
298
299    public Memoable copy()
300    {
301        return new SHA224Digest(this);
302    }
303
304    public void reset(Memoable other)
305    {
306        SHA224Digest d = (SHA224Digest)other;
307
308        doCopy(d);
309    }
310}
311
312