SkipjackEngine
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Utilities;
using System;
namespace Org.BouncyCastle.Crypto.Engines
{
public sealed class SkipjackEngine : IBlockCipher
{
private const int BLOCK_SIZE = 8;
private static readonly short[] ftable = new short[256] {
163,
215,
9,
131,
248,
72,
246,
244,
179,
33,
21,
120,
153,
177,
175,
249,
231,
45,
77,
138,
206,
76,
202,
46,
82,
149,
217,
30,
78,
56,
68,
40,
10,
223,
2,
160,
23,
241,
96,
104,
18,
183,
122,
195,
233,
250,
61,
83,
150,
132,
107,
186,
242,
99,
154,
25,
124,
174,
229,
245,
247,
22,
106,
162,
57,
182,
123,
15,
193,
147,
129,
27,
238,
180,
26,
234,
208,
145,
47,
184,
85,
185,
218,
133,
63,
65,
191,
224,
90,
88,
128,
95,
102,
11,
216,
144,
53,
213,
192,
167,
51,
6,
101,
105,
69,
0,
148,
86,
109,
152,
155,
118,
151,
252,
178,
194,
176,
254,
219,
32,
225,
235,
214,
228,
221,
71,
74,
29,
66,
237,
158,
110,
73,
60,
205,
67,
39,
210,
7,
212,
222,
199,
103,
24,
137,
203,
48,
31,
141,
198,
143,
170,
200,
116,
220,
201,
93,
92,
49,
164,
112,
136,
97,
44,
159,
13,
43,
135,
80,
130,
84,
100,
38,
125,
3,
64,
52,
75,
28,
115,
209,
196,
253,
59,
204,
251,
127,
171,
230,
62,
91,
165,
173,
4,
35,
156,
20,
81,
34,
240,
41,
121,
113,
126,
255,
140,
14,
226,
12,
239,
188,
114,
117,
111,
55,
161,
236,
211,
142,
98,
139,
134,
16,
232,
8,
119,
17,
190,
146,
79,
36,
197,
50,
54,
157,
207,
243,
166,
187,
172,
94,
108,
169,
19,
87,
37,
181,
227,
189,
168,
58,
1,
5,
89,
42,
70
};
private int[] key0;
private int[] key1;
private int[] key2;
private int[] key3;
private bool encrypting;
public string AlgorithmName => "SKIPJACK";
public void Init(bool forEncryption, ICipherParameters parameters)
{
KeyParameter obj = parameters as KeyParameter;
if (obj == null)
throw new ArgumentException("invalid parameter passed to SKIPJACK init - " + Platform.GetTypeName(parameters));
byte[] key = obj.GetKey();
encrypting = forEncryption;
key0 = new int[32];
key1 = new int[32];
key2 = new int[32];
key3 = new int[32];
for (int i = 0; i < 32; i++) {
key0[i] = key[i * 4 % 10];
key1[i] = key[(i * 4 + 1) % 10];
key2[i] = key[(i * 4 + 2) % 10];
key3[i] = key[(i * 4 + 3) % 10];
}
}
public int GetBlockSize()
{
return 8;
}
public int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff)
{
if (key1 == null)
throw new InvalidOperationException("SKIPJACK engine not initialised");
Check.DataLength(input, inOff, 8, "input buffer too short");
Check.OutputLength(output, outOff, 8, "output buffer too short");
if (encrypting)
EncryptBlock(input, inOff, output, outOff);
else
DecryptBlock(input, inOff, output, outOff);
return 8;
}
private int G(int k, int w)
{
int num = (w >> 8) & 255;
int num2 = w & 255;
int num3 = ftable[num2 ^ key0[k]] ^ num;
int num4 = ftable[num3 ^ key1[k]] ^ num2;
int num5 = ftable[num4 ^ key2[k]] ^ num3;
int num6 = ftable[num5 ^ key3[k]] ^ num4;
return (num5 << 8) + num6;
}
private int EncryptBlock(byte[] input, int inOff, byte[] outBytes, int outOff)
{
int num = (input[inOff] << 8) + (input[inOff + 1] & 255);
int num2 = (input[inOff + 2] << 8) + (input[inOff + 3] & 255);
int num3 = (input[inOff + 4] << 8) + (input[inOff + 5] & 255);
int num4 = (input[inOff + 6] << 8) + (input[inOff + 7] & 255);
int num5 = 0;
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 8; j++) {
int num6 = num4;
num4 = num3;
num3 = num2;
num2 = G(num5, num);
num = (num2 ^ num6 ^ (num5 + 1));
num5++;
}
for (int k = 0; k < 8; k++) {
int num7 = num4;
num4 = num3;
num3 = (num ^ num2 ^ (num5 + 1));
num2 = G(num5, num);
num = num7;
num5++;
}
}
outBytes[outOff] = (byte)(num >> 8);
outBytes[outOff + 1] = (byte)num;
outBytes[outOff + 2] = (byte)(num2 >> 8);
outBytes[outOff + 3] = (byte)num2;
outBytes[outOff + 4] = (byte)(num3 >> 8);
outBytes[outOff + 5] = (byte)num3;
outBytes[outOff + 6] = (byte)(num4 >> 8);
outBytes[outOff + 7] = (byte)num4;
return 8;
}
private int DecryptBlock(byte[] input, int inOff, byte[] outBytes, int outOff)
{
int num = (input[inOff] << 8) + (input[inOff + 1] & 255);
int num2 = (input[inOff + 2] << 8) + (input[inOff + 3] & 255);
int num3 = (input[inOff + 4] << 8) + (input[inOff + 5] & 255);
int num4 = (input[inOff + 6] << 8) + (input[inOff + 7] & 255);
int num5 = 31;
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 8; j++) {
int num6 = num3;
num3 = num4;
num4 = num;
num = H(num5, num2);
num2 = (num ^ num6 ^ (num5 + 1));
num5--;
}
for (int k = 0; k < 8; k++) {
int num7 = num3;
num3 = num4;
num4 = (num2 ^ num ^ (num5 + 1));
num = H(num5, num2);
num2 = num7;
num5--;
}
}
outBytes[outOff] = (byte)(num >> 8);
outBytes[outOff + 1] = (byte)num;
outBytes[outOff + 2] = (byte)(num2 >> 8);
outBytes[outOff + 3] = (byte)num2;
outBytes[outOff + 4] = (byte)(num3 >> 8);
outBytes[outOff + 5] = (byte)num3;
outBytes[outOff + 6] = (byte)(num4 >> 8);
outBytes[outOff + 7] = (byte)num4;
return 8;
}
private int H(int k, int w)
{
int num = w & 255;
int num2 = (w >> 8) & 255;
int num3 = ftable[num2 ^ key3[k]] ^ num;
int num4 = ftable[num3 ^ key2[k]] ^ num2;
int num5 = ftable[num4 ^ key1[k]] ^ num3;
return ((ftable[num5 ^ key0[k]] ^ num4) << 8) + num5;
}
}
}