001: package org.bouncycastle.crypto.macs;
002:
003: import org.bouncycastle.crypto.CipherParameters;
004: import org.bouncycastle.crypto.DataLengthException;
005: import org.bouncycastle.crypto.Mac;
006: import org.bouncycastle.crypto.params.KeyParameter;
007: import org.bouncycastle.crypto.params.ParametersWithSBox;
008:
009: /**
010: * implementation of GOST 28147-89 MAC
011: */
012: public class GOST28147Mac implements Mac {
013: private int blockSize = 8;
014: private int macSize = 4;
015: private int bufOff;
016: private byte[] buf;
017: private byte[] mac;
018: private boolean firstStep = true;
019: private int[] workingKey = null;
020:
021: //
022: // This is default S-box - E_A.
023: private byte S[] = { 0x9, 0x6, 0x3, 0x2, 0x8, 0xB, 0x1, 0x7, 0xA,
024: 0x4, 0xE, 0xF, 0xC, 0x0, 0xD, 0x5, 0x3, 0x7, 0xE, 0x9, 0x8,
025: 0xA, 0xF, 0x0, 0x5, 0x2, 0x6, 0xC, 0xB, 0x4, 0xD, 0x1, 0xE,
026: 0x4, 0x6, 0x2, 0xB, 0x3, 0xD, 0x8, 0xC, 0xF, 0x5, 0xA, 0x0,
027: 0x7, 0x1, 0x9, 0xE, 0x7, 0xA, 0xC, 0xD, 0x1, 0x3, 0x9, 0x0,
028: 0x2, 0xB, 0x4, 0xF, 0x8, 0x5, 0x6, 0xB, 0x5, 0x1, 0x9, 0x8,
029: 0xD, 0xF, 0x0, 0xE, 0x4, 0x2, 0x3, 0xC, 0x7, 0xA, 0x6, 0x3,
030: 0xA, 0xD, 0xC, 0x1, 0x2, 0x0, 0xB, 0x7, 0x5, 0x9, 0x4, 0x8,
031: 0xF, 0xE, 0x6, 0x1, 0xD, 0x2, 0x9, 0x7, 0xA, 0x6, 0x0, 0x8,
032: 0xC, 0x4, 0x5, 0xF, 0x3, 0xB, 0xE, 0xB, 0xA, 0xF, 0x5, 0x0,
033: 0xC, 0xE, 0x8, 0x6, 0x2, 0x3, 0x9, 0x1, 0x7, 0xD, 0x4 };
034:
035: public GOST28147Mac() {
036: mac = new byte[blockSize];
037:
038: buf = new byte[blockSize];
039: bufOff = 0;
040: }
041:
042: private int[] generateWorkingKey(byte[] userKey) {
043: if (userKey.length != 32) {
044: throw new IllegalArgumentException(
045: "Key length invalid. Key needs to be 32 byte - 256 bit!!!");
046: }
047:
048: int key[] = new int[8];
049: for (int i = 0; i != 8; i++) {
050: key[i] = bytesToint(userKey, i * 4);
051: }
052:
053: return key;
054: }
055:
056: public void init(CipherParameters params)
057: throws IllegalArgumentException {
058: reset();
059: buf = new byte[blockSize];
060: if (params instanceof ParametersWithSBox) {
061: ParametersWithSBox param = (ParametersWithSBox) params;
062:
063: //
064: // Set the S-Box
065: //
066: System.arraycopy(param.getSBox(), 0, this .S, 0, param
067: .getSBox().length);
068:
069: //
070: // set key if there is one
071: //
072: if (param.getParameters() != null) {
073: workingKey = generateWorkingKey(((KeyParameter) param
074: .getParameters()).getKey());
075: }
076: } else if (params instanceof KeyParameter) {
077: workingKey = generateWorkingKey(((KeyParameter) params)
078: .getKey());
079: } else {
080: throw new IllegalArgumentException(
081: "invalid parameter passed to GOST28147 init - "
082: + params.getClass().getName());
083: }
084: }
085:
086: public String getAlgorithmName() {
087: return "GOST28147Mac";
088: }
089:
090: public int getMacSize() {
091: return macSize;
092: }
093:
094: private int gost28147_mainStep(int n1, int key) {
095: int cm = (key + n1); // CM1
096:
097: // S-box replacing
098:
099: int om = S[0 + ((cm >> (0 * 4)) & 0xF)] << (0 * 4);
100: om += S[16 + ((cm >> (1 * 4)) & 0xF)] << (1 * 4);
101: om += S[32 + ((cm >> (2 * 4)) & 0xF)] << (2 * 4);
102: om += S[48 + ((cm >> (3 * 4)) & 0xF)] << (3 * 4);
103: om += S[64 + ((cm >> (4 * 4)) & 0xF)] << (4 * 4);
104: om += S[80 + ((cm >> (5 * 4)) & 0xF)] << (5 * 4);
105: om += S[96 + ((cm >> (6 * 4)) & 0xF)] << (6 * 4);
106: om += S[112 + ((cm >> (7 * 4)) & 0xF)] << (7 * 4);
107:
108: return om << 11 | om >>> (32 - 11); // 11-leftshift
109: }
110:
111: private void gost28147MacFunc(int[] workingKey, byte[] in,
112: int inOff, byte[] out, int outOff) {
113: int N1, N2, tmp; //tmp -> for saving N1
114: N1 = bytesToint(in, inOff);
115: N2 = bytesToint(in, inOff + 4);
116:
117: for (int k = 0; k < 2; k++) // 1-16 steps
118: {
119: for (int j = 0; j < 8; j++) {
120: tmp = N1;
121: N1 = N2 ^ gost28147_mainStep(N1, workingKey[j]); // CM2
122: N2 = tmp;
123: }
124: }
125:
126: intTobytes(N1, out, outOff);
127: intTobytes(N2, out, outOff + 4);
128: }
129:
130: //array of bytes to type int
131: private int bytesToint(byte[] in, int inOff) {
132: return ((in[inOff + 3] << 24) & 0xff000000)
133: + ((in[inOff + 2] << 16) & 0xff0000)
134: + ((in[inOff + 1] << 8) & 0xff00) + (in[inOff] & 0xff);
135: }
136:
137: //int to array of bytes
138: private void intTobytes(int num, byte[] out, int outOff) {
139: out[outOff + 3] = (byte) (num >>> 24);
140: out[outOff + 2] = (byte) (num >>> 16);
141: out[outOff + 1] = (byte) (num >>> 8);
142: out[outOff] = (byte) num;
143: }
144:
145: private byte[] CM5func(byte[] buf, int bufOff, byte[] mac) {
146: byte[] sum = new byte[buf.length - bufOff];
147:
148: System.arraycopy(buf, bufOff, sum, 0, mac.length);
149:
150: for (int i = 0; i != mac.length; i++) {
151: sum[i] = (byte) (sum[i] ^ mac[i]);
152: }
153:
154: return sum;
155: }
156:
157: public void update(byte in) throws IllegalStateException {
158: if (bufOff == buf.length) {
159: byte[] sumbuf = new byte[buf.length];
160: System.arraycopy(buf, 0, sumbuf, 0, mac.length);
161:
162: if (firstStep) {
163: firstStep = false;
164: } else {
165: sumbuf = CM5func(buf, 0, mac);
166: }
167:
168: gost28147MacFunc(workingKey, sumbuf, 0, mac, 0);
169: bufOff = 0;
170: }
171:
172: buf[bufOff++] = in;
173: }
174:
175: public void update(byte[] in, int inOff, int len)
176: throws DataLengthException, IllegalStateException {
177: if (len < 0) {
178: throw new IllegalArgumentException(
179: "Can't have a negative input length!");
180: }
181:
182: int gapLen = blockSize - bufOff;
183:
184: if (len > gapLen) {
185: System.arraycopy(in, inOff, buf, bufOff, gapLen);
186:
187: byte[] sumbuf = new byte[buf.length];
188: System.arraycopy(buf, 0, sumbuf, 0, mac.length);
189:
190: if (firstStep) {
191: firstStep = false;
192: } else {
193: sumbuf = CM5func(buf, 0, mac);
194: }
195:
196: gost28147MacFunc(workingKey, sumbuf, 0, mac, 0);
197:
198: bufOff = 0;
199: len -= gapLen;
200: inOff += gapLen;
201:
202: while (len > blockSize) {
203: sumbuf = CM5func(in, inOff, mac);
204: gost28147MacFunc(workingKey, sumbuf, 0, mac, 0);
205:
206: len -= blockSize;
207: inOff += blockSize;
208: }
209: }
210:
211: System.arraycopy(in, inOff, buf, bufOff, len);
212:
213: bufOff += len;
214: }
215:
216: public int doFinal(byte[] out, int outOff)
217: throws DataLengthException, IllegalStateException {
218: //padding with zero
219: while (bufOff < blockSize) {
220: buf[bufOff] = 0;
221: bufOff++;
222: }
223:
224: byte[] sumbuf = new byte[buf.length];
225: System.arraycopy(buf, 0, sumbuf, 0, mac.length);
226:
227: if (firstStep) {
228: firstStep = false;
229: } else {
230: sumbuf = CM5func(buf, 0, mac);
231: }
232:
233: gost28147MacFunc(workingKey, sumbuf, 0, mac, 0);
234:
235: System.arraycopy(mac, (mac.length / 2) - macSize, out, outOff,
236: macSize);
237:
238: reset();
239:
240: return macSize;
241: }
242:
243: public void reset() {
244: /*
245: * clean the buffer.
246: */
247: for (int i = 0; i < buf.length; i++) {
248: buf[i] = 0;
249: }
250:
251: bufOff = 0;
252:
253: firstStep = true;
254: }
255: }
|