001: package org.bouncycastle.crypto.digests;
002:
003: import org.bouncycastle.crypto.BlockCipher;
004: import org.bouncycastle.crypto.ExtendedDigest;
005: import org.bouncycastle.crypto.engines.GOST28147Engine;
006: import org.bouncycastle.crypto.params.KeyParameter;
007: import org.bouncycastle.crypto.params.ParametersWithSBox;
008:
009: /**
010: * implementation of GOST R 34.11-94
011: */
012: public class GOST3411Digest implements ExtendedDigest {
013: private static final int DIGEST_LENGTH = 32;
014:
015: private byte[] H = new byte[32], L = new byte[32],
016: M = new byte[32], Sum = new byte[32];
017: private byte[][] C = new byte[4][32];
018:
019: private byte[] xBuf = new byte[32];
020: private int xBufOff;
021: private long byteCount;
022:
023: private BlockCipher cipher = new GOST28147Engine();
024:
025: /**
026: * Standard constructor
027: */
028: public GOST3411Digest() {
029: cipher.init(true, new ParametersWithSBox(null, GOST28147Engine
030: .getSBox("D-A")));
031:
032: reset();
033: }
034:
035: /**
036: * Copy constructor. This will copy the state of the provided
037: * message digest.
038: */
039: public GOST3411Digest(GOST3411Digest t) {
040: cipher.init(true, new ParametersWithSBox(null, GOST28147Engine
041: .getSBox("D-A")));
042:
043: reset();
044:
045: System.arraycopy(t.H, 0, this .H, 0, t.H.length);
046: System.arraycopy(t.L, 0, this .L, 0, t.L.length);
047: System.arraycopy(t.M, 0, this .M, 0, t.M.length);
048: System.arraycopy(t.Sum, 0, this .Sum, 0, t.Sum.length);
049: System.arraycopy(t.C[1], 0, this .C[1], 0, t.C[1].length);
050: System.arraycopy(t.C[2], 0, this .C[2], 0, t.C[2].length);
051: System.arraycopy(t.C[3], 0, this .C[3], 0, t.C[3].length);
052: System.arraycopy(t.xBuf, 0, this .xBuf, 0, t.xBuf.length);
053:
054: this .xBufOff = t.xBufOff;
055: this .byteCount = t.byteCount;
056: }
057:
058: public String getAlgorithmName() {
059: return "GOST3411";
060: }
061:
062: public int getDigestSize() {
063: return DIGEST_LENGTH;
064: }
065:
066: public void update(byte in) {
067: xBuf[xBufOff++] = in;
068: if (xBufOff == xBuf.length) {
069: sumByteArray(xBuf); // calc sum M
070: processBlock(xBuf, 0);
071: xBufOff = 0;
072: }
073: byteCount++;
074: }
075:
076: public void update(byte[] in, int inOff, int len) {
077: while ((xBufOff != 0) && (len > 0)) {
078: update(in[inOff]);
079: inOff++;
080: len--;
081: }
082:
083: while (len > xBuf.length) {
084: System.arraycopy(in, inOff, xBuf, 0, xBuf.length);
085:
086: sumByteArray(xBuf); // calc sum M
087: processBlock(xBuf, 0);
088: inOff += xBuf.length;
089: len -= xBuf.length;
090: byteCount += xBuf.length;
091: }
092:
093: // load in the remainder.
094: while (len > 0) {
095: update(in[inOff]);
096: inOff++;
097: len--;
098: }
099: }
100:
101: // (i + 1 + 4(k - 1)) = 8i + k i = 0-3, k = 1-8
102: private byte[] K = new byte[32];
103:
104: private byte[] P(byte[] in) {
105: for (int k = 0; k < 8; k++) {
106: K[4 * k] = in[k];
107: K[1 + 4 * k] = in[8 + k];
108: K[2 + 4 * k] = in[16 + k];
109: K[3 + 4 * k] = in[24 + k];
110: }
111:
112: return K;
113: }
114:
115: //A (x) = (x0 ^ x1) || x3 || x2 || x1
116: byte[] a = new byte[8];
117:
118: private byte[] A(byte[] in) {
119: for (int j = 0; j < 8; j++) {
120: a[j] = (byte) (in[j] ^ in[j + 8]);
121: }
122:
123: System.arraycopy(in, 8, in, 0, 24);
124: System.arraycopy(a, 0, in, 24, 8);
125:
126: return in;
127: }
128:
129: //Encrypt function, ECB mode
130: private void E(byte[] key, byte[] s, int sOff, byte[] in, int inOff) {
131: cipher.init(true, new KeyParameter(key));
132:
133: cipher.processBlock(in, inOff, s, sOff);
134: }
135:
136: // (in:) n16||..||n1 ==> (out:) n1^n2^n3^n4^n13^n16||n16||..||n2
137: short[] wS = new short[16], w_S = new short[16];
138:
139: private void fw(byte[] in) {
140: cpyBytesToShort(in, wS);
141: w_S[15] = (short) (wS[0] ^ wS[1] ^ wS[2] ^ wS[3] ^ wS[12] ^ wS[15]);
142: System.arraycopy(wS, 1, w_S, 0, 15);
143: cpyShortToBytes(w_S, in);
144: }
145:
146: // block processing
147: byte[] S = new byte[32];
148: byte[] U = new byte[32], V = new byte[32], W = new byte[32];
149:
150: protected void processBlock(byte[] in, int inOff) {
151: System.arraycopy(in, inOff, M, 0, 32);
152:
153: //key step 1
154:
155: // H = h3 || h2 || h1 || h0
156: // S = s3 || s2 || s1 || s0
157: System.arraycopy(H, 0, U, 0, 32);
158: System.arraycopy(M, 0, V, 0, 32);
159: for (int j = 0; j < 32; j++) {
160: W[j] = (byte) (U[j] ^ V[j]);
161: }
162: // Encrypt gost28147-ECB
163: E(P(W), S, 0, H, 0); // s0 = EK0 [h0]
164:
165: //keys step 2,3,4
166: for (int i = 1; i < 4; i++) {
167: byte[] tmpA = A(U);
168: for (int j = 0; j < 32; j++) {
169: U[j] = (byte) (tmpA[j] ^ C[i][j]);
170: }
171: V = A(A(V));
172: for (int j = 0; j < 32; j++) {
173: W[j] = (byte) (U[j] ^ V[j]);
174: }
175: // Encrypt gost28147-ECB
176: E(P(W), S, i * 8, H, i * 8); // si = EKi [hi]
177: }
178:
179: // x(M, H) = y61(H^y(M^y12(S)))
180: for (int n = 0; n < 12; n++) {
181: fw(S);
182: }
183: for (int n = 0; n < 32; n++) {
184: S[n] = (byte) (S[n] ^ M[n]);
185: }
186:
187: fw(S);
188:
189: for (int n = 0; n < 32; n++) {
190: S[n] = (byte) (H[n] ^ S[n]);
191: }
192: for (int n = 0; n < 61; n++) {
193: fw(S);
194: }
195: System.arraycopy(S, 0, H, 0, H.length);
196: }
197:
198: private void finish() {
199: LongToBytes(byteCount * 8, L, 0); // get length into L (byteCount * 8 = bitCount)
200:
201: while (xBufOff != 0) {
202: update((byte) 0);
203: }
204:
205: processBlock(L, 0);
206: processBlock(Sum, 0);
207: }
208:
209: public int doFinal(byte[] out, int outOff) {
210: finish();
211:
212: System.arraycopy(H, 0, out, outOff, H.length);
213:
214: reset();
215:
216: return DIGEST_LENGTH;
217: }
218:
219: /**
220: * reset the chaining variables to the IV values.
221: */
222: private static final byte[] C2 = { 0x00, (byte) 0xFF, 0x00,
223: (byte) 0xFF, 0x00, (byte) 0xFF, 0x00, (byte) 0xFF,
224: (byte) 0xFF, 0x00, (byte) 0xFF, 0x00, (byte) 0xFF, 0x00,
225: (byte) 0xFF, 0x00, 0x00, (byte) 0xFF, (byte) 0xFF, 0x00,
226: (byte) 0xFF, 0x00, 0x00, (byte) 0xFF, (byte) 0xFF, 0x00,
227: 0x00, 0x00, (byte) 0xFF, (byte) 0xFF, 0x00, (byte) 0xFF };
228:
229: public void reset() {
230: byteCount = 0;
231: xBufOff = 0;
232:
233: for (int i = 0; i < H.length; i++) {
234: H[i] = 0; // start vector H
235: }
236: for (int i = 0; i < L.length; i++) {
237: L[i] = 0;
238: }
239: for (int i = 0; i < M.length; i++) {
240: M[i] = 0;
241: }
242: for (int i = 0; i < C[1].length; i++) {
243: C[1][i] = 0; // real index C = +1 because index array with 0.
244: }
245: for (int i = 0; i < C[3].length; i++) {
246: C[3][i] = 0;
247: }
248: for (int i = 0; i < Sum.length; i++) {
249: Sum[i] = 0;
250: }
251: for (int i = 0; i < xBuf.length; i++) {
252: xBuf[i] = 0;
253: }
254:
255: System.arraycopy(C2, 0, C[2], 0, C2.length);
256: }
257:
258: // 256 bitsblock modul -> (Sum + a mod (2^256))
259: private void sumByteArray(byte[] in) {
260: int carry = 0;
261:
262: for (int i = 0; i != Sum.length; i++) {
263: int sum = (Sum[i] & 0xff) + (in[i] & 0xff) + carry;
264:
265: Sum[i] = (byte) sum;
266:
267: carry = sum >>> 8;
268: }
269: }
270:
271: private void LongToBytes(long r, byte[] out, int outOff) {
272: out[outOff + 7] = (byte) (r >> 56);
273: out[outOff + 6] = (byte) (r >> 48);
274: out[outOff + 5] = (byte) (r >> 40);
275: out[outOff + 4] = (byte) (r >> 32);
276: out[outOff + 3] = (byte) (r >> 24);
277: out[outOff + 2] = (byte) (r >> 16);
278: out[outOff + 1] = (byte) (r >> 8);
279: out[outOff] = (byte) r;
280: }
281:
282: private void cpyBytesToShort(byte[] S, short[] wS) {
283: for (int i = 0; i < S.length / 2; i++) {
284: wS[i] = (short) (((S[i * 2 + 1] << 8) & 0xFF00) | (S[i * 2] & 0xFF));
285: }
286: }
287:
288: private void cpyShortToBytes(short[] wS, byte[] S) {
289: for (int i = 0; i < S.length / 2; i++) {
290: S[i * 2 + 1] = (byte) (wS[i] >> 8);
291: S[i * 2] = (byte) wS[i];
292: }
293: }
294:
295: public int getByteLength() {
296: return 32;
297: }
298: }
|