1 package org.bouncycastle.crypto.digests;
2 
3 import org.bouncycastle.crypto.BlockCipher;
4 import org.bouncycastle.crypto.ExtendedDigest;
5 import org.bouncycastle.crypto.engines.GOST28147Engine;
6 import org.bouncycastle.crypto.params.KeyParameter;
7 import org.bouncycastle.crypto.params.ParametersWithSBox;
8 import org.bouncycastle.util.Arrays;
9 import org.bouncycastle.util.Memoable;
10 import org.bouncycastle.util.Pack;
11 
12 /**
13  * implementation of GOST R 34.11-94
14  */
15 public class GOST3411Digest
16     implements ExtendedDigest, Memoable
17 {
18     private static final int    DIGEST_LENGTH = 32;
19 
20     private byte[]   H = new byte[32], L = new byte[32],
21                      M = new byte[32], Sum = new byte[32];
22     private byte[][] C = new byte[4][32];
23 
24     private byte[]  xBuf = new byte[32];
25     private int  xBufOff;
26     private long byteCount;
27 
28     private BlockCipher cipher = new GOST28147Engine();
29     private byte[] sBox;
30 
31     /**
32      * Standard constructor
33      */
GOST3411Digest()34     public GOST3411Digest()
35     {
36         sBox = GOST28147Engine.getSBox("D-A");
37         cipher.init(true, new ParametersWithSBox(null, sBox));
38 
39         reset();
40     }
41 
42     /**
43      * Constructor to allow use of a particular sbox with GOST28147
44      * @see GOST28147Engine#getSBox(String)
45      */
GOST3411Digest(byte[] sBoxParam)46     public GOST3411Digest(byte[] sBoxParam)
47     {
48         sBox = Arrays.clone(sBoxParam);
49         cipher.init(true, new ParametersWithSBox(null, sBox));
50 
51         reset();
52     }
53 
54     /**
55      * Copy constructor.  This will copy the state of the provided
56      * message digest.
57      */
GOST3411Digest(GOST3411Digest t)58     public GOST3411Digest(GOST3411Digest t)
59     {
60         reset(t);
61     }
62 
getAlgorithmName()63     public String getAlgorithmName()
64     {
65         return "GOST3411";
66     }
67 
getDigestSize()68     public int getDigestSize()
69     {
70         return DIGEST_LENGTH;
71     }
72 
update(byte in)73     public void update(byte in)
74     {
75         xBuf[xBufOff++] = in;
76         if (xBufOff == xBuf.length)
77         {
78             sumByteArray(xBuf); // calc sum M
79             processBlock(xBuf, 0);
80             xBufOff = 0;
81         }
82         byteCount++;
83     }
84 
update(byte[] in, int inOff, int len)85     public void update(byte[] in, int inOff, int len)
86     {
87         while ((xBufOff != 0) && (len > 0))
88         {
89             update(in[inOff]);
90             inOff++;
91             len--;
92         }
93 
94         while (len > xBuf.length)
95         {
96             System.arraycopy(in, inOff, xBuf, 0, xBuf.length);
97 
98             sumByteArray(xBuf); // calc sum M
99             processBlock(xBuf, 0);
100             inOff += xBuf.length;
101             len -= xBuf.length;
102             byteCount += xBuf.length;
103         }
104 
105         // load in the remainder.
106         while (len > 0)
107         {
108             update(in[inOff]);
109             inOff++;
110             len--;
111         }
112     }
113 
114     // (i + 1 + 4(k - 1)) = 8i + k      i = 0-3, k = 1-8
115     private byte[] K = new byte[32];
116 
P(byte[] in)117     private byte[] P(byte[] in)
118     {
119         for(int k = 0; k < 8; k++)
120         {
121             K[4*k] = in[k];
122             K[1 + 4*k] = in[ 8 + k];
123             K[2 + 4*k] = in[16 + k];
124             K[3 + 4*k] = in[24 + k];
125         }
126 
127         return K;
128     }
129 
130     //A (x) = (x0 ^ x1) || x3 || x2 || x1
131     byte[] a = new byte[8];
A(byte[] in)132     private byte[] A(byte[] in)
133     {
134         for(int j=0; j<8; j++)
135         {
136             a[j]=(byte)(in[j] ^ in[j+8]);
137         }
138 
139         System.arraycopy(in, 8, in, 0, 24);
140         System.arraycopy(a, 0, in, 24, 8);
141 
142         return in;
143     }
144 
145     //Encrypt function, ECB mode
E(byte[] key, byte[] s, int sOff, byte[] in, int inOff)146     private void E(byte[] key, byte[] s, int sOff, byte[] in, int inOff)
147     {
148         cipher.init(true, new KeyParameter(key));
149 
150         cipher.processBlock(in, inOff, s, sOff);
151     }
152 
153     // (in:) n16||..||n1 ==> (out:) n1^n2^n3^n4^n13^n16||n16||..||n2
154     short[] wS = new short[16], w_S = new short[16];
155 
fw(byte[] in)156     private void fw(byte[] in)
157     {
158         cpyBytesToShort(in, wS);
159         w_S[15] = (short)(wS[0] ^ wS[1] ^ wS[2] ^ wS[3] ^ wS[12] ^ wS[15]);
160         System.arraycopy(wS, 1, w_S, 0, 15);
161         cpyShortToBytes(w_S, in);
162     }
163 
164     // block processing
165     byte[] S = new byte[32];
166     byte[] U = new byte[32], V = new byte[32], W = new byte[32];
167 
processBlock(byte[] in, int inOff)168     protected void processBlock(byte[] in, int inOff)
169     {
170         System.arraycopy(in, inOff, M, 0, 32);
171 
172         //key step 1
173 
174         // H = h3 || h2 || h1 || h0
175         // S = s3 || s2 || s1 || s0
176         System.arraycopy(H, 0, U, 0, 32);
177         System.arraycopy(M, 0, V, 0, 32);
178         for (int j=0; j<32; j++)
179         {
180             W[j] = (byte)(U[j]^V[j]);
181         }
182         // Encrypt gost28147-ECB
183         E(P(W), S, 0, H, 0); // s0 = EK0 [h0]
184 
185         //keys step 2,3,4
186         for (int i=1; i<4; i++)
187         {
188             byte[] tmpA = A(U);
189             for (int j=0; j<32; j++)
190             {
191                 U[j] = (byte)(tmpA[j] ^ C[i][j]);
192             }
193             V = A(A(V));
194             for (int j=0; j<32; j++)
195             {
196                 W[j] = (byte)(U[j]^V[j]);
197             }
198             // Encrypt gost28147-ECB
199             E(P(W), S, i * 8, H, i * 8); // si = EKi [hi]
200         }
201 
202         // x(M, H) = y61(H^y(M^y12(S)))
203         for(int n = 0; n < 12; n++)
204         {
205             fw(S);
206         }
207         for(int n = 0; n < 32; n++)
208         {
209             S[n] = (byte)(S[n] ^ M[n]);
210         }
211 
212         fw(S);
213 
214         for(int n = 0; n < 32; n++)
215         {
216             S[n] = (byte)(H[n] ^ S[n]);
217         }
218         for(int n = 0; n < 61; n++)
219         {
220             fw(S);
221         }
222         System.arraycopy(S, 0, H, 0, H.length);
223     }
224 
finish()225     private void finish()
226     {
227         Pack.longToLittleEndian(byteCount * 8, L, 0); // get length into L (byteCount * 8 = bitCount)
228 
229         while (xBufOff != 0)
230         {
231             update((byte)0);
232         }
233 
234         processBlock(L, 0);
235         processBlock(Sum, 0);
236     }
237 
doFinal( byte[] out, int outOff)238     public int doFinal(
239         byte[]  out,
240         int     outOff)
241     {
242         finish();
243 
244         System.arraycopy(H, 0, out, outOff, H.length);
245 
246         reset();
247 
248         return DIGEST_LENGTH;
249     }
250 
251     /**
252      * reset the chaining variables to the IV values.
253      */
254     private static final byte[]  C2 = {
255        0x00,(byte)0xFF,0x00,(byte)0xFF,0x00,(byte)0xFF,0x00,(byte)0xFF,
256        (byte)0xFF,0x00,(byte)0xFF,0x00,(byte)0xFF,0x00,(byte)0xFF,0x00,
257        0x00,(byte)0xFF,(byte)0xFF,0x00,(byte)0xFF,0x00,0x00,(byte)0xFF,
258        (byte)0xFF,0x00,0x00,0x00,(byte)0xFF,(byte)0xFF,0x00,(byte)0xFF};
259 
reset()260     public void reset()
261     {
262         byteCount = 0;
263         xBufOff = 0;
264 
265         for(int i=0; i<H.length; i++)
266         {
267             H[i] = 0;  // start vector H
268         }
269         for(int i=0; i<L.length; i++)
270         {
271             L[i] = 0;
272         }
273         for(int i=0; i<M.length; i++)
274         {
275             M[i] = 0;
276         }
277         for(int i=0; i<C[1].length; i++)
278         {
279             C[1][i] = 0;  // real index C = +1 because index array with 0.
280         }
281         for(int i=0; i<C[3].length; i++)
282         {
283             C[3][i] = 0;
284         }
285         for(int i=0; i<Sum.length; i++)
286         {
287             Sum[i] = 0;
288         }
289         for(int i = 0; i < xBuf.length; i++)
290         {
291             xBuf[i] = 0;
292         }
293 
294         System.arraycopy(C2, 0, C[2], 0, C2.length);
295     }
296 
297     //  256 bitsblock modul -> (Sum + a mod (2^256))
sumByteArray(byte[] in)298     private void sumByteArray(byte[] in)
299     {
300         int carry = 0;
301 
302         for (int i = 0; i != Sum.length; i++)
303         {
304             int sum = (Sum[i] & 0xff) + (in[i] & 0xff) + carry;
305 
306             Sum[i] = (byte)sum;
307 
308             carry = sum >>> 8;
309         }
310     }
311 
cpyBytesToShort(byte[] S, short[] wS)312     private void cpyBytesToShort(byte[] S, short[] wS)
313     {
314         for(int i=0; i<S.length/2; i++)
315         {
316             wS[i] = (short)(((S[i*2+1]<<8)&0xFF00)|(S[i*2]&0xFF));
317         }
318     }
319 
cpyShortToBytes(short[] wS, byte[] S)320     private void cpyShortToBytes(short[] wS, byte[] S)
321     {
322         for(int i=0; i<S.length/2; i++)
323         {
324             S[i*2 + 1] = (byte)(wS[i] >> 8);
325             S[i*2] = (byte)wS[i];
326         }
327     }
328 
getByteLength()329    public int getByteLength()
330    {
331       return 32;
332    }
333 
copy()334     public Memoable copy()
335     {
336         return new GOST3411Digest(this);
337     }
338 
reset(Memoable other)339     public void reset(Memoable other)
340     {
341         GOST3411Digest t = (GOST3411Digest)other;
342 
343         this.sBox = t.sBox;
344         cipher.init(true, new ParametersWithSBox(null, sBox));
345 
346         reset();
347 
348         System.arraycopy(t.H, 0, this.H, 0, t.H.length);
349         System.arraycopy(t.L, 0, this.L, 0, t.L.length);
350         System.arraycopy(t.M, 0, this.M, 0, t.M.length);
351         System.arraycopy(t.Sum, 0, this.Sum, 0, t.Sum.length);
352         System.arraycopy(t.C[1], 0, this.C[1], 0, t.C[1].length);
353         System.arraycopy(t.C[2], 0, this.C[2], 0, t.C[2].length);
354         System.arraycopy(t.C[3], 0, this.C[3], 0, t.C[3].length);
355         System.arraycopy(t.xBuf, 0, this.xBuf, 0, t.xBuf.length);
356 
357         this.xBufOff = t.xBufOff;
358         this.byteCount = t.byteCount;
359     }
360 }
361 
362 
363