View Javadoc
1   /*
2    * GordianKnot: Security Suite
3    * Copyright 2012-2026. Tony Washer
4    *
5    * Licensed under the Apache License, Version 2.0 (the "License"); you may not
6    * use this file except in compliance with the License.  You may obtain a copy
7    * of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
14   * License for the specific language governing permissions and limitations under
15   * the License.
16   */
17  package io.github.tonywasher.joceanus.gordianknot.impl.ext.engines;
18  
19  import org.bouncycastle.crypto.BlockCipher;
20  import org.bouncycastle.crypto.CipherParameters;
21  import org.bouncycastle.crypto.DataLengthException;
22  import org.bouncycastle.crypto.OutputLengthException;
23  import org.bouncycastle.crypto.params.KeyParameter;
24  
25  /**
26   * MARSEngine ported from the reference C implementation, found at https://embeddedsw.net/Cipher_Reference_Home.html.
27   */
28  @SuppressWarnings("checkstyle:MagicNumber")
29  public class GordianMARSEngine
30          implements BlockCipher {
31      /**
32       * BlockSize in bits.
33       */
34      private static final int BLOCKSIZE = 128;
35  
36      /**
37       * BlockSize in bytes.
38       */
39      private static final int BLOCKSIZEB = (BLOCKSIZE / 8);
40  
41      /**
42       * BlockSize in Integers.
43       */
44      private static final int INTLENGTH = BLOCKSIZEB / Integer.BYTES;
45  
46      /**
47       * Initialised flag.
48       */
49      private boolean initialised;
50  
51      /**
52       * Encryption flag.
53       */
54      private boolean forEncryption;
55  
56      /**
57       * Input buffer.
58       */
59      private final int[] input = new int[INTLENGTH];
60  
61      /**
62       * Output buffer.
63       */
64      private final int[] output = new int[INTLENGTH];
65  
66      /**
67       * SBox.
68       */
69      private static final int[] S_BOX = {
70              0x09d0c479, 0x28c8ffe0, 0x84aa6c39, 0x9dad7287, /* 0x000 */
71              0x7dff9be3, 0xd4268361, 0xc96da1d4, 0x7974cc93,
72              0x85d0582e, 0x2a4b5705, 0x1ca16a62, 0xc3bd279d,
73              0x0f1f25e5, 0x5160372f, 0xc695c1fb, 0x4d7ff1e4,
74              0xae5f6bf4, 0x0d72ee46, 0xff23de8a, 0xb1cf8e83, /* 0x010 */
75              0xf14902e2, 0x3e981e42, 0x8bf53eb6, 0x7f4bf8ac,
76              0x83631f83, 0x25970205, 0x76afe784, 0x3a7931d4,
77              0x4f846450, 0x5c64c3f6, 0x210a5f18, 0xc6986a26,
78              0x28f4e826, 0x3a60a81c, 0xd340a664, 0x7ea820c4, /* 0x020 */
79              0x526687c5, 0x7eddd12b, 0x32a11d1d, 0x9c9ef086,
80              0x80f6e831, 0xab6f04ad, 0x56fb9b53, 0x8b2e095c,
81              0xb68556ae, 0xd2250b0d, 0x294a7721, 0xe21fb253,
82              0xae136749, 0xe82aae86, 0x93365104, 0x99404a66, /* 0x030 */
83              0x78a784dc, 0xb69ba84b, 0x04046793, 0x23db5c1e,
84              0x46cae1d6, 0x2fe28134, 0x5a223942, 0x1863cd5b,
85              0xc190c6e3, 0x07dfb846, 0x6eb88816, 0x2d0dcc4a,
86              0xa4ccae59, 0x3798670d, 0xcbfa9493, 0x4f481d45, /* 0x040 */
87              0xeafc8ca8, 0xdb1129d6, 0xb0449e20, 0x0f5407fb,
88              0x6167d9a8, 0xd1f45763, 0x4daa96c3, 0x3bec5958,
89              0xababa014, 0xb6ccd201, 0x38d6279f, 0x02682215,
90              0x8f376cd5, 0x092c237e, 0xbfc56593, 0x32889d2c, /* 0x050 */
91              0x854b3e95, 0x05bb9b43, 0x7dcd5dcd, 0xa02e926c,
92              0xfae527e5, 0x36a1c330, 0x3412e1ae, 0xf257f462,
93              0x3c4f1d71, 0x30a2e809, 0x68e5f551, 0x9c61ba44,
94              0x5ded0ab8, 0x75ce09c8, 0x9654f93e, 0x698c0cca, /* 0x060 */
95              0x243cb3e4, 0x2b062b97, 0x0f3b8d9e, 0x00e050df,
96              0xfc5d6166, 0xe35f9288, 0xc079550d, 0x0591aee8,
97              0x8e531e74, 0x75fe3578, 0x2f6d829a, 0xf60b21ae,
98              0x95e8eb8d, 0x6699486b, 0x901d7d9b, 0xfd6d6e31, /* 0x070 */
99              0x1090acef, 0xe0670dd8, 0xdab2e692, 0xcd6d4365,
100             0xe5393514, 0x3af345f0, 0x6241fc4d, 0x460da3a3,
101             0x7bcf3729, 0x8bf1d1e0, 0x14aac070, 0x1587ed55,
102             0x3afd7d3e, 0xd2f29e01, 0x29a9d1f6, 0xefb10c53, /* 0x080 */
103             0xcf3b870f, 0xb414935c, 0x664465ed, 0x024acac7,
104             0x59a744c1, 0x1d2936a7, 0xdc580aa6, 0xcf574ca8,
105             0x040a7a10, 0x6cd81807, 0x8a98be4c, 0xaccea063,
106             0xc33e92b5, 0xd1e0e03d, 0xb322517e, 0x2092bd13, /* 0x090 */
107             0x386b2c4a, 0x52e8dd58, 0x58656dfb, 0x50820371,
108             0x41811896, 0xe337ef7e, 0xd39fb119, 0xc97f0df6,
109             0x68fea01b, 0xa150a6e5, 0x55258962, 0xeb6ff41b,
110             0xd7c9cd7a, 0xa619cd9e, 0xbcf09576, 0x2672c073, /* 0x0a0 */
111             0xf003fb3c, 0x4ab7a50b, 0x1484126a, 0x487ba9b1,
112             0xa64fc9c6, 0xf6957d49, 0x38b06a75, 0xdd805fcd,
113             0x63d094cf, 0xf51c999e, 0x1aa4d343, 0xb8495294,
114             0xce9f8e99, 0xbffcd770, 0xc7c275cc, 0x378453a7, /* 0x0b0 */
115             0x7b21be33, 0x397f41bd, 0x4e94d131, 0x92cc1f98,
116             0x5915ea51, 0x99f861b7, 0xc9980a88, 0x1d74fd5f,
117             0xb0a495f8, 0x614deed0, 0xb5778eea, 0x5941792d,
118             0xfa90c1f8, 0x33f824b4, 0xc4965372, 0x3ff6d550, /* 0x0c0 */
119             0x4ca5fec0, 0x8630e964, 0x5b3fbbd6, 0x7da26a48,
120             0xb203231a, 0x04297514, 0x2d639306, 0x2eb13149,
121             0x16a45272, 0x532459a0, 0x8e5f4872, 0xf966c7d9,
122             0x07128dc0, 0x0d44db62, 0xafc8d52d, 0x06316131, /* 0x0d0 */
123             0xd838e7ce, 0x1bc41d00, 0x3a2e8c0f, 0xea83837e,
124             0xb984737d, 0x13ba4891, 0xc4f8b949, 0xa6d6acb3,
125             0xa215cdce, 0x8359838b, 0x6bd1aa31, 0xf579dd52,
126             0x21b93f93, 0xf5176781, 0x187dfdde, 0xe94aeb76, /* 0x0e0 */
127             0x2b38fd54, 0x431de1da, 0xab394825, 0x9ad3048f,
128             0xdfea32aa, 0x659473e3, 0x623f7863, 0xf3346c59,
129             0xab3ab685, 0x3346a90b, 0x6b56443e, 0xc6de01f8,
130             0x8d421fc0, 0x9b0ed10c, 0x88f1a1e9, 0x54c1f029, /* 0x0f0 */
131             0x7dead57b, 0x8d7ba426, 0x4cf5178a, 0x551a7cca,
132             0x1a9a5f08, 0xfcd651b9, 0x25605182, 0xe11fc6c3,
133             0xb6fd9676, 0x337b3027, 0xb7c8eb14, 0x9e5fd030,
134             0x6b57e354, 0xad913cf7, 0x7e16688d, 0x58872a69, /* 0x100 */
135             0x2c2fc7df, 0xe389ccc6, 0x30738df1, 0x0824a734,
136             0xe1797a8b, 0xa4a8d57b, 0x5b5d193b, 0xc8a8309b,
137             0x73f9a978, 0x73398d32, 0x0f59573e, 0xe9df2b03,
138             0xe8a5b6c8, 0x848d0704, 0x98df93c2, 0x720a1dc3, /* 0x110 */
139             0x684f259a, 0x943ba848, 0xa6370152, 0x863b5ea3,
140             0xd17b978b, 0x6d9b58ef, 0x0a700dd4, 0xa73d36bf,
141             0x8e6a0829, 0x8695bc14, 0xe35b3447, 0x933ac568,
142             0x8894b022, 0x2f511c27, 0xddfbcc3c, 0x006662b6, /* 0x120 */
143             0x117c83fe, 0x4e12b414, 0xc2bca766, 0x3a2fec10,
144             0xf4562420, 0x55792e2a, 0x46f5d857, 0xceda25ce,
145             0xc3601d3b, 0x6c00ab46, 0xefac9c28, 0xb3c35047,
146             0x611dfee3, 0x257c3207, 0xfdd58482, 0x3b14d84f, /* 0x130 */
147             0x23becb64, 0xa075f3a3, 0x088f8ead, 0x07adf158,
148             0x7796943c, 0xfacabf3d, 0xc09730cd, 0xf7679969,
149             0xda44e9ed, 0x2c854c12, 0x35935fa3, 0x2f057d9f,
150             0x690624f8, 0x1cb0bafd, 0x7b0dbdc6, 0x810f23bb, /* 0x140 */
151             0xfa929a1a, 0x6d969a17, 0x6742979b, 0x74ac7d05,
152             0x010e65c4, 0x86a3d963, 0xf907b5a0, 0xd0042bd3,
153             0x158d7d03, 0x287a8255, 0xbba8366f, 0x096edc33,
154             0x21916a7b, 0x77b56b86, 0x951622f9, 0xa6c5e650, /* 0x150 */
155             0x8cea17d1, 0xcd8c62bc, 0xa3d63433, 0x358a68fd,
156             0x0f9b9d3c, 0xd6aa295b, 0xfe33384a, 0xc000738e,
157             0xcd67eb2f, 0xe2eb6dc2, 0x97338b02, 0x06c9f246,
158             0x419cf1ad, 0x2b83c045, 0x3723f18a, 0xcb5b3089, /* 0x160 */
159             0x160bead7, 0x5d494656, 0x35f8a74b, 0x1e4e6c9e,
160             0x000399bd, 0x67466880, 0xb4174831, 0xacf423b2,
161             0xca815ab3, 0x5a6395e7, 0x302a67c5, 0x8bdb446b,
162             0x108f8fa4, 0x10223eda, 0x92b8b48b, 0x7f38d0ee, /* 0x170 */
163             0xab2701d4, 0x0262d415, 0xaf224a30, 0xb3d88aba,
164             0xf8b2c3af, 0xdaf7ef70, 0xcc97d3b7, 0xe9614b6c,
165             0x2baebff4, 0x70f687cf, 0x386c9156, 0xce092ee5,
166             0x01e87da6, 0x6ce91e6a, 0xbb7bcc84, 0xc7922c20, /* 0x180 */
167             0x9d3b71fd, 0x060e41c6, 0xd7590f15, 0x4e03bb47,
168             0x183c198e, 0x63eeb240, 0x2ddbf49a, 0x6d5cba54,
169             0x923750af, 0xf9e14236, 0x7838162b, 0x59726c72,
170             0x81b66760, 0xbb2926c1, 0x48a0ce0d, 0xa6c0496d, /* 0x190 */
171             0xad43507b, 0x718d496a, 0x9df057af, 0x44b1bde6,
172             0x054356dc, 0xde7ced35, 0xd51a138b, 0x62088cc9,
173             0x35830311, 0xc96efca2, 0x686f86ec, 0x8e77cb68,
174             0x63e1d6b8, 0xc80f9778, 0x79c491fd, 0x1b4c67f2, /* 0x1a0 */
175             0x72698d7d, 0x5e368c31, 0xf7d95e2e, 0xa1d3493f,
176             0xdcd9433e, 0x896f1552, 0x4bc4ca7a, 0xa6d1baf4,
177             0xa5a96dcc, 0x0bef8b46, 0xa169fda7, 0x74df40b7,
178             0x4e208804, 0x9a756607, 0x038e87c8, 0x20211e44, /* 0x1b0 */
179             0x8b7ad4bf, 0xc6403f35, 0x1848e36d, 0x80bdb038,
180             0x1e62891c, 0x643d2107, 0xbf04d6f8, 0x21092c8c,
181             0xf644f389, 0x0778404e, 0x7b78adb8, 0xa2c52d53,
182             0x42157abe, 0xa2253e2e, 0x7bf3f4ae, 0x80f594f9, /* 0x1c0 */
183             0x953194e7, 0x77eb92ed, 0xb3816930, 0xda8d9336,
184             0xbf447469, 0xf26d9483, 0xee6faed5, 0x71371235,
185             0xde425f73, 0xb4e59f43, 0x7dbe2d4e, 0x2d37b185,
186             0x49dc9a63, 0x98c39d98, 0x1301c9a2, 0x389b1bbf, /* 0x1d0 */
187             0x0c18588d, 0xa421c1ba, 0x7aa3865c, 0x71e08558,
188             0x3c5cfcaa, 0x7d239ca4, 0x0297d9dd, 0xd7dc2830,
189             0x4b37802b, 0x7428ab54, 0xaeee0347, 0x4b3fbb85,
190             0x692f2f08, 0x134e578e, 0x36d9e0bf, 0xae8b5fcf, /* 0x1e0 */
191             0xedb93ecf, 0x2b27248e, 0x170eb1ef, 0x7dc57fd6,
192             0x1e760f16, 0xb1136601, 0x864e1b9b, 0xd7ea7319,
193             0x3ab871bd, 0xcfa4d76f, 0xe31bd782, 0x0dbeb469,
194             0xabb96061, 0x5370f85d, 0xffb07e37, 0xda30d0fb, /* 0x1f0 */
195             0xebc977b6, 0x0b98b40f, 0x3a4d0fe6, 0xdf4fc26b,
196             0x159cf22a, 0xc298d6e2, 0x2b78ef6a, 0x61a94ac0,
197             0xab561187, 0x14eea0f0, 0xdf0d4164, 0x19af70ee
198     };
199 
200     /**
201      * VK.
202      */
203     private final int[] vk = {
204             0x09d0c479, 0x28c8ffe0, 0x84aa6c39, 0x9dad7287, 0x7dff9be3, 0xd4268361, /* 6 */
205             0xc96da1d4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20 */
206             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 37 */
207             0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 47 */
208     };
209 
210     /**
211      * lKey.
212      */
213     private final int[] lKey = new int[40];
214 
215     private static int rotr(final int x, final int n) {
216         return ((x >>> n) | (x << (32 - n)));
217     }
218 
219     private static int rotl(final int x, final int n) {
220         return ((x << n) | (x >>> (32 - n)));
221     }
222 
223     private static void fMix(final int[] vals, final int offset) {
224         /* Decide correct offsets */
225         int myOffset = offset;
226         final int a = myOffset++ % 4;
227         final int b = myOffset++ % 4;
228         final int c = myOffset++ % 4;
229         final int d = myOffset % 4;
230 
231         /* Perform mix */
232         int r = rotr(vals[a], 8);
233         vals[b] ^= S_BOX[vals[a] & 255];
234         vals[b] += S_BOX[(r & 255) + 256];
235         r = rotr(vals[a], 16);
236         vals[a] = rotr(vals[a], 24);
237         vals[c] += S_BOX[r & 255];
238         vals[d] ^= S_BOX[(vals[a] & 255) + 256];
239     }
240 
241     private static void bMix(final int[] vals, final int offset) {
242         /* Decide correct offsets */
243         int myOffset = offset;
244         final int a = myOffset++ % 4;
245         final int b = myOffset++ % 4;
246         final int c = myOffset++ % 4;
247         final int d = myOffset % 4;
248 
249         /* Perform mix */
250         int r = rotl(vals[a], 8);
251         vals[b] ^= S_BOX[(vals[a] & 255) + 256];
252         vals[c] -= S_BOX[r & 255];
253         r = rotl(vals[a], 16);
254         vals[a] = rotl(vals[a], 24);
255         vals[d] -= S_BOX[(r & 255) + 256];
256         vals[d] ^= S_BOX[vals[a] & 255];
257     }
258 
259     private void fKtr(final int[] vals, final int i, final int offset, final boolean doSwitch) {
260         /* Decide correct offsets */
261         int myOffset = offset;
262         final int a = myOffset++ % 4;
263         int b = myOffset++ % 4;
264         final int c = myOffset++ % 4;
265         int d = myOffset % 4;
266 
267         /* Switch b and c if required */
268         if (doSwitch) {
269             final int temp = b;
270             b = d;
271             d = temp;
272         }
273 
274         /* Perform operation */
275         final int m = vals[a] + lKey[i];
276         vals[a] = rotl(vals[a], 13);
277         int r = vals[a] * lKey[i + 1];
278         int l = S_BOX[m & 511];
279         r = rotl(r, 5);
280         vals[c] += rotl(m, r);
281         l ^= r;
282         r = rotl(r, 5);
283         l ^= r;
284         vals[d] ^= r;
285         vals[b] += rotl(l, r);
286     }
287 
288     private void rKtr(final int[] vals, final int i, final int offset, final boolean doSwitch) {
289         /* Decide correct offsets */
290         int myOffset = offset;
291         final int a = myOffset++ % 4;
292         int b = myOffset++ % 4;
293         final int c = myOffset++ % 4;
294         int d = myOffset % 4;
295 
296         /* Switch b and c if required */
297         if (doSwitch) {
298             final int temp = b;
299             b = d;
300             d = temp;
301         }
302 
303         /* Perform operation */
304         int r = vals[a] * lKey[i + 1];
305         vals[a] = rotr(vals[a], 13);
306         final int m = vals[a] + lKey[i];
307         int l = S_BOX[m & 511];
308         r = rotl(r, 5);
309         l ^= r;
310         vals[c] -= rotl(m, r);
311         r = rotl(r, 5);
312         l ^= r;
313         vals[d] ^= r;
314         vals[b] -= rotl(l, r);
315     }
316 
317     /* For a 32 bit word (x) generate a mask (m) such that a bit in */
318     /* m is set to 1 if and only if the corresponding bit in x is: */
319     /*                                                              */
320     /* 1. in a sequence of 10 or more adjacent '0' bits */
321     /* 2. in a sequence of 10 or more adjacent '1' bits */
322     /* 3. but is not either endpoint of such a sequence unless such */
323     /* an endpoint is at the top bit (bit 31) of a word and is */
324     /* in a sequence of '0' bits. */
325     /*                                                              */
326     /* The only situation in which a sequence endpoint is included */
327     /* in the mask is hence when the endpoint is at bit 31 and is */
328     /* the endpoint of a sequence of '0' bits. My thanks go to Shai */
329     /* Halevi of IBM for the neat trick (which I missed) of finding */
330     /* the '0' and '1' sequences at the same time. */
331     private static int genMask(final int x) {
332         /* if m{bn} stands for bit number bn of m, set m{bn} = 1 if */
333         /* x{bn} == x{bn+1} for 0 <= bn <= 30. That is, set a bit */
334         /* in m if the corresponding bit and the next higher bit in */
335         /* x are equal in value (set m{31} = 0). */
336         int m = (~x ^ (x >>> 1)) & 0x7fffffff;
337 
338         /* Sequences of 9 '1' bits in m now correspond to sequences */
339         /* of 10 '0's or 10 '1' bits in x. Shift and 'and' bits in */
340         /* m to find sequences of 9 or more '1' bits. As a result */
341         /* bits in m are set if they are at the bottom of sequences */
342         /* of 10 adjacent '0's or 10 adjacent '1's in x. */
343         m &= (m >>> 1) & (m >>> 2);
344         m &= (m >>> 3) & (m >>> 6);
345 
346         /* return if mask is empty - no key fixing needed */
347         if (m == 0) {
348             return 0;
349         }
350 
351         /* We need the internal bits in each continuous sequence of */
352         /* matching bits (that is the bits less the two endpoints). */
353         /* We thus propagate each set bit into the 8 internal bits */
354         /* that it represents, starting 1 left and finsihing 8 left */
355         /* of its position. */
356         m <<= 1;
357         m |= (m << 1);
358         m |= (m << 2);
359         m |= (m << 4);
360 
361         /* m is now correct except for the odd behaviour of bit 31, */
362         /* that is, it will be set if it is in a sequence of 10 or */
363         /* more '0's and clear otherwise. */
364         m |= (m << 1) & ~x & 0x80000000;
365         return m & 0xfffffffc;
366     }
367 
368     /* My thanks to Louis Granboulan for spotting an error in the */
369     /* previous version of set_key. */
370     private int[] setKey(final int[] inKey, final int keyLen) {
371         int w;
372         int m = keyLen / 32 - 1;
373         for (int i = 0, j = 0; i < 39; ++i) {
374             vk[i + 7] = rotl(vk[i] ^ vk[i + 5], 3) ^ inKey[j] ^ i;
375             j = (j == m
376                     ? 0
377                     : j + 1);
378         }
379 
380         vk[46] = keyLen / 32;
381 
382         for (int j = 0; j < 7; ++j) {
383             for (int i = 1; i < 40; ++i) {
384                 vk[i + 7] = rotl(vk[i + 7] + S_BOX[vk[i + 6] & 511], 9);
385             }
386             vk[7] = rotl(vk[7] + S_BOX[vk[46] & 511], 9);
387         }
388 
389         for (int i = 0, j = 0; i < 40; ++i) {
390             lKey[j] = vk[i + 7];
391             j = (j < 33
392                     ? j + 7
393                     : j - 33);
394         }
395 
396         for (int i = 5; i < 37; i += 2) {
397             w = lKey[i] | 3;
398             m = genMask(w);
399             if (m != 0) {
400                 w ^= (rotl(S_BOX[265 + (lKey[i] & 3)], lKey[i + 3] & 31) & m);
401             }
402             lKey[i] = w;
403         }
404         return lKey;
405     }
406 
407     private void encrypt(final int[] inBlk, final int[] outBlk) {
408         final int[] vals = new int[4];
409 
410         vals[0] = inBlk[0] + lKey[0];
411         vals[1] = inBlk[1] + lKey[1];
412         vals[2] = inBlk[2] + lKey[2];
413         vals[3] = inBlk[3] + lKey[3];
414 
415         fMix(vals, 0);
416         vals[0] += vals[3];
417         fMix(vals, 1);
418         vals[1] += vals[2];
419         fMix(vals, 2);
420         fMix(vals, 3);
421 
422         fMix(vals, 0);
423         vals[0] += vals[3];
424         fMix(vals, 1);
425         vals[1] += vals[2];
426         fMix(vals, 2);
427         fMix(vals, 3);
428 
429         fKtr(vals, 4, 0, false);
430         fKtr(vals, 6, 1, false);
431         fKtr(vals, 8, 2, false);
432         fKtr(vals, 10, 3, false);
433         fKtr(vals, 12, 0, false);
434         fKtr(vals, 14, 1, false);
435         fKtr(vals, 16, 2, false);
436         fKtr(vals, 18, 3, false);
437         fKtr(vals, 20, 0, true);
438         fKtr(vals, 22, 1, true);
439         fKtr(vals, 24, 2, true);
440         fKtr(vals, 26, 3, true);
441         fKtr(vals, 28, 0, true);
442         fKtr(vals, 30, 1, true);
443         fKtr(vals, 32, 2, true);
444         fKtr(vals, 34, 3, true);
445 
446         bMix(vals, 0);
447         bMix(vals, 1);
448         vals[2] -= vals[1];
449         bMix(vals, 2);
450         vals[3] -= vals[0];
451         bMix(vals, 3);
452 
453         bMix(vals, 0);
454         bMix(vals, 1);
455         vals[2] -= vals[1];
456         bMix(vals, 2);
457         vals[3] -= vals[0];
458         bMix(vals, 3);
459 
460         outBlk[0] = vals[0] - lKey[36];
461         outBlk[1] = vals[1] - lKey[37];
462         outBlk[2] = vals[2] - lKey[38];
463         outBlk[3] = vals[3] - lKey[39];
464     }
465 
466     private void decrypt(final int[] inBlk, final int[] outBlk) {
467         final int[] vals = new int[4];
468 
469         vals[3] = inBlk[0] + lKey[36];
470         vals[2] = inBlk[1] + lKey[37];
471         vals[1] = inBlk[2] + lKey[38];
472         vals[0] = inBlk[3] + lKey[39];
473 
474         fMix(vals, 0);
475         vals[0] += vals[3];
476         fMix(vals, 1);
477         vals[1] += vals[2];
478         fMix(vals, 2);
479         fMix(vals, 3);
480 
481         fMix(vals, 0);
482         vals[0] += vals[3];
483         fMix(vals, 1);
484         vals[1] += vals[2];
485         fMix(vals, 2);
486         fMix(vals, 3);
487 
488         rKtr(vals, 34, 0, false);
489         rKtr(vals, 32, 1, false);
490         rKtr(vals, 30, 2, false);
491         rKtr(vals, 28, 3, false);
492         rKtr(vals, 26, 0, false);
493         rKtr(vals, 24, 1, false);
494         rKtr(vals, 22, 2, false);
495         rKtr(vals, 20, 3, false);
496         rKtr(vals, 18, 0, true);
497         rKtr(vals, 16, 1, true);
498         rKtr(vals, 14, 2, true);
499         rKtr(vals, 12, 3, true);
500         rKtr(vals, 10, 0, true);
501         rKtr(vals, 8, 1, true);
502         rKtr(vals, 6, 2, true);
503         rKtr(vals, 4, 3, true);
504 
505         bMix(vals, 0);
506         bMix(vals, 1);
507         vals[2] -= vals[1];
508         bMix(vals, 2);
509         vals[3] -= vals[0];
510         bMix(vals, 3);
511         bMix(vals, 0);
512         bMix(vals, 1);
513         vals[2] -= vals[1];
514         bMix(vals, 2);
515         vals[3] -= vals[0];
516         bMix(vals, 3);
517 
518         outBlk[0] = vals[3] - lKey[0];
519         outBlk[1] = vals[2] - lKey[1];
520         outBlk[2] = vals[1] - lKey[2];
521         outBlk[3] = vals[0] - lKey[3];
522     }
523 
524     /**
525      * Set key from bytes.
526      *
527      * @param pKey the key Bytes.
528      */
529     public void setKey(final byte[] pKey) {
530         /* Determine the key and array length */
531         int keyLength = pKey.length;
532         final int intLength = keyLength / Integer.BYTES;
533         keyLength *= Byte.SIZE;
534 
535 
536         /* map cipher key to initial key state */
537         final int[] myIntKey = new int[intLength];
538         for (int i = 0, pos = 0; i < intLength; i++, pos += Integer.BYTES) {
539             myIntKey[i] = ((pKey[pos + 3] & 255) << 24)
540                     | ((pKey[pos + 2] & 255) << 16)
541                     | ((pKey[pos + 1] & 255) << 8)
542                     | (pKey[pos] & 255);
543         }
544 
545         /* Set the key */
546         setKey(myIntKey, keyLength);
547     }
548 
549     /**
550      * Build inputArray from input.
551      *
552      * @param pInput  the input Bytes.
553      * @param pOffset the offset
554      */
555     private void buildInput(final byte[] pInput, final int pOffset) {
556         /* map input to intArray */
557         for (int i = 0, pos = pOffset; i < INTLENGTH; i++, pos += Integer.BYTES) {
558             input[i] = ((pInput[pos + 3] & 255) << 24)
559                     | ((pInput[pos + 2] & 255) << 16)
560                     | ((pInput[pos + 1] & 255) << 8)
561                     | (pInput[pos] & 255);
562         }
563     }
564 
565     /**
566      * Build output from intArray.
567      *
568      * @param pOutput the output array.
569      * @param pOffset the offset
570      */
571     private void buildOutput(final byte[] pOutput, final int pOffset) {
572         /* Determine the key and array length */
573         final int intLength = 4;
574 
575         /* map input to intArray */
576         for (int i = 0, pos = pOffset; i < intLength; i++, pos += Integer.BYTES) {
577             final int w = output[i];
578             pOutput[pos] = (byte) (w);
579             pOutput[pos + 1] = (byte) (w >> 8);
580             pOutput[pos + 2] = (byte) (w >> 16);
581             pOutput[pos + 3] = (byte) (w >> 24);
582         }
583     }
584 
585     @Override
586     public String getAlgorithmName() {
587         return "MARS";
588     }
589 
590     @Override
591     public int getBlockSize() {
592         return BLOCKSIZEB;
593     }
594 
595     @Override
596     public void init(final boolean forEncrypt, final CipherParameters pParameters) throws IllegalArgumentException {
597         /* Reject invalid parameters */
598         if (!(pParameters instanceof KeyParameter)) {
599             throw new IllegalArgumentException("Invalid parameter passed to MARS init - "
600                     + pParameters.getClass().getName());
601         }
602 
603         /* Determine keySize */
604         final byte[] keyBytes = ((KeyParameter) pParameters).getKey();
605         final int keyBitSize = keyBytes.length * Byte.SIZE;
606         if (keyBitSize != 128 && keyBitSize != 192 && keyBitSize != 256) {
607             throw new IllegalArgumentException("KeyBitSize must be 128, 192 or 256");
608         }
609 
610         /* Set up key */
611         initialised = true;
612         this.forEncryption = forEncrypt;
613         setKey(keyBytes);
614     }
615 
616     @Override
617     public int processBlock(final byte[] in, final int inOff, final byte[] out, final int outOff) throws DataLengthException, IllegalStateException {
618         if (!initialised) {
619             throw new IllegalStateException("MARS engine not initialised");
620         }
621         if (inOff > (in.length - BLOCKSIZEB)) {
622             throw new DataLengthException("input buffer too short");
623         }
624         if (outOff > (out.length - BLOCKSIZEB)) {
625             throw new OutputLengthException("output buffer too short");
626         }
627 
628         buildInput(in, inOff);
629         if (forEncryption) {
630             encrypt(input, output);
631         } else {
632             decrypt(input, output);
633         }
634         buildOutput(out, outOff);
635         return BLOCKSIZEB;
636     }
637 
638     @Override
639     public void reset() {
640         /* NoOp */
641     }
642 }