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.CipherParameters;
20  import org.bouncycastle.crypto.DataLengthException;
21  import org.bouncycastle.crypto.OutputLengthException;
22  import org.bouncycastle.crypto.StreamCipher;
23  import org.bouncycastle.crypto.params.KeyParameter;
24  import org.bouncycastle.crypto.params.ParametersWithIV;
25  import org.bouncycastle.util.Memoable;
26  
27  /**
28   * Zuc128Engine implementation.
29   * Based on https://www.gsma.com/aboutus/wp-content/uploads/2014/12/eea3eia3zucv16.pdf
30   * Donated to BouncyCastle
31   */
32  @SuppressWarnings("checkstyle:MagicNumber")
33  public class GordianZuc128Engine implements StreamCipher, Memoable {
34      /**
35       * s-box0.
36       */
37      private static final byte[] S0 = {
38              (byte) 0x3e, (byte) 0x72, (byte) 0x5b, (byte) 0x47, (byte) 0xca, (byte) 0xe0, (byte) 0x00, (byte) 0x33,
39              (byte) 0x04, (byte) 0xd1, (byte) 0x54, (byte) 0x98, (byte) 0x09, (byte) 0xb9, (byte) 0x6d, (byte) 0xcb,
40              (byte) 0x7b, (byte) 0x1b, (byte) 0xf9, (byte) 0x32, (byte) 0xaf, (byte) 0x9d, (byte) 0x6a, (byte) 0xa5,
41              (byte) 0xb8, (byte) 0x2d, (byte) 0xfc, (byte) 0x1d, (byte) 0x08, (byte) 0x53, (byte) 0x03, (byte) 0x90,
42              (byte) 0x4d, (byte) 0x4e, (byte) 0x84, (byte) 0x99, (byte) 0xe4, (byte) 0xce, (byte) 0xd9, (byte) 0x91,
43              (byte) 0xdd, (byte) 0xb6, (byte) 0x85, (byte) 0x48, (byte) 0x8b, (byte) 0x29, (byte) 0x6e, (byte) 0xac,
44              (byte) 0xcd, (byte) 0xc1, (byte) 0xf8, (byte) 0x1e, (byte) 0x73, (byte) 0x43, (byte) 0x69, (byte) 0xc6,
45              (byte) 0xb5, (byte) 0xbd, (byte) 0xfd, (byte) 0x39, (byte) 0x63, (byte) 0x20, (byte) 0xd4, (byte) 0x38,
46              (byte) 0x76, (byte) 0x7d, (byte) 0xb2, (byte) 0xa7, (byte) 0xcf, (byte) 0xed, (byte) 0x57, (byte) 0xc5,
47              (byte) 0xf3, (byte) 0x2c, (byte) 0xbb, (byte) 0x14, (byte) 0x21, (byte) 0x06, (byte) 0x55, (byte) 0x9b,
48              (byte) 0xe3, (byte) 0xef, (byte) 0x5e, (byte) 0x31, (byte) 0x4f, (byte) 0x7f, (byte) 0x5a, (byte) 0xa4,
49              (byte) 0x0d, (byte) 0x82, (byte) 0x51, (byte) 0x49, (byte) 0x5f, (byte) 0xba, (byte) 0x58, (byte) 0x1c,
50              (byte) 0x4a, (byte) 0x16, (byte) 0xd5, (byte) 0x17, (byte) 0xa8, (byte) 0x92, (byte) 0x24, (byte) 0x1f,
51              (byte) 0x8c, (byte) 0xff, (byte) 0xd8, (byte) 0xae, (byte) 0x2e, (byte) 0x01, (byte) 0xd3, (byte) 0xad,
52              (byte) 0x3b, (byte) 0x4b, (byte) 0xda, (byte) 0x46, (byte) 0xeb, (byte) 0xc9, (byte) 0xde, (byte) 0x9a,
53              (byte) 0x8f, (byte) 0x87, (byte) 0xd7, (byte) 0x3a, (byte) 0x80, (byte) 0x6f, (byte) 0x2f, (byte) 0xc8,
54              (byte) 0xb1, (byte) 0xb4, (byte) 0x37, (byte) 0xf7, (byte) 0x0a, (byte) 0x22, (byte) 0x13, (byte) 0x28,
55              (byte) 0x7c, (byte) 0xcc, (byte) 0x3c, (byte) 0x89, (byte) 0xc7, (byte) 0xc3, (byte) 0x96, (byte) 0x56,
56              (byte) 0x07, (byte) 0xbf, (byte) 0x7e, (byte) 0xf0, (byte) 0x0b, (byte) 0x2b, (byte) 0x97, (byte) 0x52,
57              (byte) 0x35, (byte) 0x41, (byte) 0x79, (byte) 0x61, (byte) 0xa6, (byte) 0x4c, (byte) 0x10, (byte) 0xfe,
58              (byte) 0xbc, (byte) 0x26, (byte) 0x95, (byte) 0x88, (byte) 0x8a, (byte) 0xb0, (byte) 0xa3, (byte) 0xfb,
59              (byte) 0xc0, (byte) 0x18, (byte) 0x94, (byte) 0xf2, (byte) 0xe1, (byte) 0xe5, (byte) 0xe9, (byte) 0x5d,
60              (byte) 0xd0, (byte) 0xdc, (byte) 0x11, (byte) 0x66, (byte) 0x64, (byte) 0x5c, (byte) 0xec, (byte) 0x59,
61              (byte) 0x42, (byte) 0x75, (byte) 0x12, (byte) 0xf5, (byte) 0x74, (byte) 0x9c, (byte) 0xaa, (byte) 0x23,
62              (byte) 0x0e, (byte) 0x86, (byte) 0xab, (byte) 0xbe, (byte) 0x2a, (byte) 0x02, (byte) 0xe7, (byte) 0x67,
63              (byte) 0xe6, (byte) 0x44, (byte) 0xa2, (byte) 0x6c, (byte) 0xc2, (byte) 0x93, (byte) 0x9f, (byte) 0xf1,
64              (byte) 0xf6, (byte) 0xfa, (byte) 0x36, (byte) 0xd2, (byte) 0x50, (byte) 0x68, (byte) 0x9e, (byte) 0x62,
65              (byte) 0x71, (byte) 0x15, (byte) 0x3d, (byte) 0xd6, (byte) 0x40, (byte) 0xc4, (byte) 0xe2, (byte) 0x0f,
66              (byte) 0x8e, (byte) 0x83, (byte) 0x77, (byte) 0x6b, (byte) 0x25, (byte) 0x05, (byte) 0x3f, (byte) 0x0c,
67              (byte) 0x30, (byte) 0xea, (byte) 0x70, (byte) 0xb7, (byte) 0xa1, (byte) 0xe8, (byte) 0xa9, (byte) 0x65,
68              (byte) 0x8d, (byte) 0x27, (byte) 0x1a, (byte) 0xdb, (byte) 0x81, (byte) 0xb3, (byte) 0xa0, (byte) 0xf4,
69              (byte) 0x45, (byte) 0x7a, (byte) 0x19, (byte) 0xdf, (byte) 0xee, (byte) 0x78, (byte) 0x34, (byte) 0x60
70      };
71  
72      /**
73       * s-box1.
74       */
75      private static final byte[] S1 = {
76              (byte) 0x55, (byte) 0xc2, (byte) 0x63, (byte) 0x71, (byte) 0x3b, (byte) 0xc8, (byte) 0x47, (byte) 0x86,
77              (byte) 0x9f, (byte) 0x3c, (byte) 0xda, (byte) 0x5b, (byte) 0x29, (byte) 0xaa, (byte) 0xfd, (byte) 0x77,
78              (byte) 0x8c, (byte) 0xc5, (byte) 0x94, (byte) 0x0c, (byte) 0xa6, (byte) 0x1a, (byte) 0x13, (byte) 0x00,
79              (byte) 0xe3, (byte) 0xa8, (byte) 0x16, (byte) 0x72, (byte) 0x40, (byte) 0xf9, (byte) 0xf8, (byte) 0x42,
80              (byte) 0x44, (byte) 0x26, (byte) 0x68, (byte) 0x96, (byte) 0x81, (byte) 0xd9, (byte) 0x45, (byte) 0x3e,
81              (byte) 0x10, (byte) 0x76, (byte) 0xc6, (byte) 0xa7, (byte) 0x8b, (byte) 0x39, (byte) 0x43, (byte) 0xe1,
82              (byte) 0x3a, (byte) 0xb5, (byte) 0x56, (byte) 0x2a, (byte) 0xc0, (byte) 0x6d, (byte) 0xb3, (byte) 0x05,
83              (byte) 0x22, (byte) 0x66, (byte) 0xbf, (byte) 0xdc, (byte) 0x0b, (byte) 0xfa, (byte) 0x62, (byte) 0x48,
84              (byte) 0xdd, (byte) 0x20, (byte) 0x11, (byte) 0x06, (byte) 0x36, (byte) 0xc9, (byte) 0xc1, (byte) 0xcf,
85              (byte) 0xf6, (byte) 0x27, (byte) 0x52, (byte) 0xbb, (byte) 0x69, (byte) 0xf5, (byte) 0xd4, (byte) 0x87,
86              (byte) 0x7f, (byte) 0x84, (byte) 0x4c, (byte) 0xd2, (byte) 0x9c, (byte) 0x57, (byte) 0xa4, (byte) 0xbc,
87              (byte) 0x4f, (byte) 0x9a, (byte) 0xdf, (byte) 0xfe, (byte) 0xd6, (byte) 0x8d, (byte) 0x7a, (byte) 0xeb,
88              (byte) 0x2b, (byte) 0x53, (byte) 0xd8, (byte) 0x5c, (byte) 0xa1, (byte) 0x14, (byte) 0x17, (byte) 0xfb,
89              (byte) 0x23, (byte) 0xd5, (byte) 0x7d, (byte) 0x30, (byte) 0x67, (byte) 0x73, (byte) 0x08, (byte) 0x09,
90              (byte) 0xee, (byte) 0xb7, (byte) 0x70, (byte) 0x3f, (byte) 0x61, (byte) 0xb2, (byte) 0x19, (byte) 0x8e,
91              (byte) 0x4e, (byte) 0xe5, (byte) 0x4b, (byte) 0x93, (byte) 0x8f, (byte) 0x5d, (byte) 0xdb, (byte) 0xa9,
92              (byte) 0xad, (byte) 0xf1, (byte) 0xae, (byte) 0x2e, (byte) 0xcb, (byte) 0x0d, (byte) 0xfc, (byte) 0xf4,
93              (byte) 0x2d, (byte) 0x46, (byte) 0x6e, (byte) 0x1d, (byte) 0x97, (byte) 0xe8, (byte) 0xd1, (byte) 0xe9,
94              (byte) 0x4d, (byte) 0x37, (byte) 0xa5, (byte) 0x75, (byte) 0x5e, (byte) 0x83, (byte) 0x9e, (byte) 0xab,
95              (byte) 0x82, (byte) 0x9d, (byte) 0xb9, (byte) 0x1c, (byte) 0xe0, (byte) 0xcd, (byte) 0x49, (byte) 0x89,
96              (byte) 0x01, (byte) 0xb6, (byte) 0xbd, (byte) 0x58, (byte) 0x24, (byte) 0xa2, (byte) 0x5f, (byte) 0x38,
97              (byte) 0x78, (byte) 0x99, (byte) 0x15, (byte) 0x90, (byte) 0x50, (byte) 0xb8, (byte) 0x95, (byte) 0xe4,
98              (byte) 0xd0, (byte) 0x91, (byte) 0xc7, (byte) 0xce, (byte) 0xed, (byte) 0x0f, (byte) 0xb4, (byte) 0x6f,
99              (byte) 0xa0, (byte) 0xcc, (byte) 0xf0, (byte) 0x02, (byte) 0x4a, (byte) 0x79, (byte) 0xc3, (byte) 0xde,
100             (byte) 0xa3, (byte) 0xef, (byte) 0xea, (byte) 0x51, (byte) 0xe6, (byte) 0x6b, (byte) 0x18, (byte) 0xec,
101             (byte) 0x1b, (byte) 0x2c, (byte) 0x80, (byte) 0xf7, (byte) 0x74, (byte) 0xe7, (byte) 0xff, (byte) 0x21,
102             (byte) 0x5a, (byte) 0x6a, (byte) 0x54, (byte) 0x1e, (byte) 0x41, (byte) 0x31, (byte) 0x92, (byte) 0x35,
103             (byte) 0xc4, (byte) 0x33, (byte) 0x07, (byte) 0x0a, (byte) 0xba, (byte) 0x7e, (byte) 0x0e, (byte) 0x34,
104             (byte) 0x88, (byte) 0xb1, (byte) 0x98, (byte) 0x7c, (byte) 0xf3, (byte) 0x3d, (byte) 0x60, (byte) 0x6c,
105             (byte) 0x7b, (byte) 0xca, (byte) 0xd3, (byte) 0x1f, (byte) 0x32, (byte) 0x65, (byte) 0x04, (byte) 0x28,
106             (byte) 0x64, (byte) 0xbe, (byte) 0x85, (byte) 0x9b, (byte) 0x2f, (byte) 0x59, (byte) 0x8a, (byte) 0xd7,
107             (byte) 0xb0, (byte) 0x25, (byte) 0xac, (byte) 0xaf, (byte) 0x12, (byte) 0x03, (byte) 0xe2, (byte) 0xf2
108     };
109 
110     /**
111      * The constants D.
112      */
113     private static final short[] EK_D = {
114             0x44D7, 0x26BC, 0x626B, 0x135E, 0x5789, 0x35E2, 0x7135, 0x09AF,
115             0x4D78, 0x2F13, 0x6BC4, 0x1AF1, 0x5E26, 0x3C4D, 0x789A, 0x47AC
116     };
117 
118     /**
119      * LFSR State.
120      */
121     private final int[] lfsrState = new int[16];
122 
123     /**
124      * F state.
125      */
126     private final int[] fState = new int[2];
127 
128     /**
129      * BRC State.
130      */
131     private final int[] brcState = new int[4];
132 
133     /**
134      * index of next byte in keyStream.
135      */
136     private int theIndex;
137 
138     /**
139      * Advanced stream.
140      */
141     private final byte[] keyStream = new byte[Integer.BYTES];
142 
143     /**
144      * The iterations.
145      */
146     private int theIterations;
147 
148     /**
149      * Reset state.
150      */
151     private GordianZuc128Engine theResetState;
152 
153     /**
154      * Constructor.
155      */
156     public GordianZuc128Engine() {
157     }
158 
159     /**
160      * Constructor.
161      *
162      * @param pSource the source engine
163      */
164     GordianZuc128Engine(final GordianZuc128Engine pSource) {
165         reset(pSource);
166     }
167 
168     /**
169      * initialise a Zuc cipher.
170      *
171      * @param forEncryption whether or not we are for encryption.
172      * @param params        the parameters required to set up the cipher.
173      * @throws IllegalArgumentException if the params argument is inappropriate.
174      */
175     public void init(final boolean forEncryption,
176                      final CipherParameters params) {
177         /*
178          * encryption and decryption is completely symmetrical, so the 'forEncryption' is
179          * irrelevant. (Like 90% of stream ciphers)
180          */
181 
182         /* Determine parameters */
183         CipherParameters myParams = params;
184         byte[] newKey = null;
185         byte[] newIV = null;
186         if ((myParams instanceof ParametersWithIV)) {
187             final ParametersWithIV ivParams = (ParametersWithIV) myParams;
188             newIV = ivParams.getIV();
189             myParams = ivParams.getParameters();
190         }
191         if (myParams instanceof KeyParameter) {
192             final KeyParameter keyParam = (KeyParameter) myParams;
193             newKey = keyParam.getKey();
194         }
195 
196         /* Initialise engine and mark as initialised */
197         theIndex = 0;
198         theIterations = 0;
199         setKeyAndIV(newKey, newIV);
200 
201         /* Save reset state */
202         theResetState = copy();
203     }
204 
205     /**
206      * Obtain Max iterations.
207      *
208      * @return the maximum iterations
209      */
210     protected int getMaxIterations() {
211         return 2047;
212     }
213 
214     /**
215      * Obtain Algorithm Name.
216      *
217      * @return the name
218      */
219     public String getAlgorithmName() {
220         return "Zuc-128";
221     }
222 
223     /**
224      * Process bytes.
225      *
226      * @param in     the input buffer
227      * @param inOff  the starting offset in the input buffer
228      * @param len    the length of data in the input buffer
229      * @param out    the output buffer
230      * @param outOff the starting offset in the output buffer
231      * @return the number of bytes returned in the output buffer
232      */
233     public int processBytes(final byte[] in,
234                             final int inOff,
235                             final int len,
236                             final byte[] out,
237                             final int outOff) {
238         /* Check for errors */
239         if (theResetState == null) {
240             throw new IllegalStateException(getAlgorithmName() + " not initialised");
241         }
242         if ((inOff + len) > in.length) {
243             throw new DataLengthException("input buffer too short");
244         }
245         if ((outOff + len) > out.length) {
246             throw new OutputLengthException("output buffer too short");
247         }
248 
249         /* Loop through the input bytes */
250         for (int i = 0; i < len; i++) {
251             out[i + outOff] = returnByte(in[i + inOff]);
252         }
253         return len;
254     }
255 
256     /**
257      * Reset the engine.
258      */
259     public void reset() {
260         if (theResetState != null) {
261             reset(theResetState);
262         }
263     }
264 
265     /**
266      * Process single byte.
267      *
268      * @param in the input byte
269      * @return the output byte
270      */
271     public byte returnByte(final byte in) {
272         /* Make the keyStream if required */
273         if (theIndex == 0) {
274             makeKeyStream();
275         }
276 
277         /* Map the next byte and adjust index */
278         final byte out = (byte) (keyStream[theIndex] ^ in);
279         theIndex = (theIndex + 1) % Integer.BYTES;
280 
281         /* Return the mapped character */
282         return out;
283     }
284 
285     /**
286      * Encode a 32-bit value into a buffer (little-endian).
287      *
288      * @param val the value to encode
289      * @param buf the output buffer
290      * @param off the output offset
291      */
292     public static void encode32be(final int val, final byte[] buf, final int off) {
293         buf[off] = (byte) (val >> 24);
294         buf[off + 1] = (byte) (val >> 16);
295         buf[off + 2] = (byte) (val >> 8);
296         buf[off + 3] = (byte) val;
297     }
298 
299     /* ——————————————————————- */
300 
301     /**
302      * Modular add c = a + b mod (2^31 – 1).
303      *
304      * @param a value A
305      * @param b value B
306      * @return the result
307      */
308     private int addM(final int a, final int b) {
309         final int c = a + b;
310         return (c & 0x7FFFFFFF) + (c >>> 31);
311     }
312 
313     /**
314      * Multiply by power of two.
315      *
316      * @param x input value
317      * @param k the power of two
318      * @return the result
319      */
320     private static int mulByPow2(final int x, final int k) {
321         return ((((x) << k) | ((x) >>> (31 - k))) & 0x7FFFFFFF);
322     }
323 
324     /**
325      * LFSR with initialisation mode.
326      *
327      * @param u
328      */
329     private void lfsrWithInitialisationMode(final int u) {
330         int f = lfsrState[0];
331         int v = mulByPow2(lfsrState[0], 8);
332         f = addM(f, v);
333         v = mulByPow2(lfsrState[4], 20);
334         f = addM(f, v);
335         v = mulByPow2(lfsrState[10], 21);
336         f = addM(f, v);
337         v = mulByPow2(lfsrState[13], 17);
338         f = addM(f, v);
339         v = mulByPow2(lfsrState[15], 15);
340         f = addM(f, v);
341         f = addM(f, u);
342 
343         /* update the state */
344         lfsrState[0] = lfsrState[1];
345         lfsrState[1] = lfsrState[2];
346         lfsrState[2] = lfsrState[3];
347         lfsrState[3] = lfsrState[4];
348         lfsrState[4] = lfsrState[5];
349         lfsrState[5] = lfsrState[6];
350         lfsrState[6] = lfsrState[7];
351         lfsrState[7] = lfsrState[8];
352         lfsrState[8] = lfsrState[9];
353         lfsrState[9] = lfsrState[10];
354         lfsrState[10] = lfsrState[11];
355         lfsrState[11] = lfsrState[12];
356         lfsrState[12] = lfsrState[13];
357         lfsrState[13] = lfsrState[14];
358         lfsrState[14] = lfsrState[15];
359         lfsrState[15] = f;
360     }
361 
362     /**
363      * LFSR with work mode.
364      */
365     private void lfsrWithWorkMode() {
366         int f = lfsrState[0];
367         int v = mulByPow2(lfsrState[0], 8);
368         f = addM(f, v);
369         v = mulByPow2(lfsrState[4], 20);
370         f = addM(f, v);
371         v = mulByPow2(lfsrState[10], 21);
372         f = addM(f, v);
373         v = mulByPow2(lfsrState[13], 17);
374         f = addM(f, v);
375         v = mulByPow2(lfsrState[15], 15);
376         f = addM(f, v);
377 
378         /* update the state */
379         lfsrState[0] = lfsrState[1];
380         lfsrState[1] = lfsrState[2];
381         lfsrState[2] = lfsrState[3];
382         lfsrState[3] = lfsrState[4];
383         lfsrState[4] = lfsrState[5];
384         lfsrState[5] = lfsrState[6];
385         lfsrState[6] = lfsrState[7];
386         lfsrState[7] = lfsrState[8];
387         lfsrState[8] = lfsrState[9];
388         lfsrState[9] = lfsrState[10];
389         lfsrState[10] = lfsrState[11];
390         lfsrState[11] = lfsrState[12];
391         lfsrState[12] = lfsrState[13];
392         lfsrState[13] = lfsrState[14];
393         lfsrState[14] = lfsrState[15];
394         lfsrState[15] = f;
395     }
396 
397     /**
398      * BitReorganization.
399      */
400     private void bitReorganization() {
401         brcState[0] = ((lfsrState[15] & 0x7FFF8000) << 1) | (lfsrState[14] & 0xFFFF);
402         brcState[1] = ((lfsrState[11] & 0xFFFF) << 16) | (lfsrState[9] >>> 15);
403         brcState[2] = ((lfsrState[7] & 0xFFFF) << 16) | (lfsrState[5] >>> 15);
404         brcState[3] = ((lfsrState[2] & 0xFFFF) << 16) | (lfsrState[0] >>> 15);
405     }
406 
407     /**
408      * Rotate integer.
409      *
410      * @param a the integer
411      * @param k the shift
412      * @return the result
413      */
414     static int rot(final int a, final int k) {
415         return (((a) << k) | ((a) >>> (32 - k)));
416     }
417 
418     /**
419      * L1.
420      *
421      * @param x the input integer.
422      * @return the result
423      */
424     private static int l1(final int x) {
425         return (x ^ rot(x, 2) ^ rot(x, 10) ^ rot(x, 18) ^ rot(x, 24));
426     }
427 
428     /**
429      * L2.
430      *
431      * @param x the input integer.
432      * @return the result
433      */
434     private static int l2(final int x) {
435         return (x ^ rot(x, 8) ^ rot(x, 14) ^ rot(x, 22) ^ rot(x, 30));
436     }
437 
438     /**
439      * Build a 32-bit integer from constituent parts.
440      *
441      * @param a part A
442      * @param b part B
443      * @param c part C
444      * @param d part D
445      * @return the built integer
446      */
447     private static int makeU32(final byte a,
448                                final byte b,
449                                final byte c,
450                                final byte d) {
451         return (((a & 0xFF) << 24) | ((b & 0xFF) << 16) | ((c & 0xFF) << 8) | (d & 0xFF));
452     }
453 
454     /**
455      * F.
456      *
457      * @return the new state
458      */
459     int f() {
460         final int w = (brcState[0] ^ fState[0]) + fState[1];
461         final int w1 = fState[0] + brcState[1];
462         final int w2 = fState[1] ^ brcState[2];
463         final int u = l1((w1 << 16) | (w2 >>> 16));
464         final int v = l2((w2 << 16) | (w1 >>> 16));
465         fState[0] = makeU32(S0[u >>> 24], S1[(u >>> 16) & 0xFF],
466                 S0[(u >>> 8) & 0xFF], S1[u & 0xFF]);
467         fState[1] = makeU32(S0[v >>> 24], S1[(v >>> 16) & 0xFF],
468                 S0[(v >>> 8) & 0xFF], S1[v & 0xFF]);
469         return w;
470     }
471 
472     /**
473      * Build a 31-bit integer from constituent parts.
474      *
475      * @param a part A
476      * @param b part B
477      * @param c part C
478      * @return the built integer
479      */
480     private static int makeU31(final byte a,
481                                final short b,
482                                final byte c) {
483         return (((a & 0xFF) << 23) | ((b & 0xFFFF) << 8) | (c & 0xFF));
484     }
485 
486     /**
487      * Process key and IV into LFSR.
488      *
489      * @param pLFSR the LFSR
490      * @param k     the key
491      * @param iv    the iv
492      */
493     protected void setKeyAndIV(final int[] pLFSR,
494                                final byte[] k,
495                                final byte[] iv) {
496         /* Check lengths */
497         if (k == null || k.length != 16) {
498             throw new IllegalArgumentException("A key of 16 bytes is needed");
499         }
500         if (iv == null || iv.length != 16) {
501             throw new IllegalArgumentException("An IV of 16 bytes is needed");
502         }
503 
504         /* expand key */
505         lfsrState[0] = makeU31(k[0], EK_D[0], iv[0]);
506         lfsrState[1] = makeU31(k[1], EK_D[1], iv[1]);
507         lfsrState[2] = makeU31(k[2], EK_D[2], iv[2]);
508         lfsrState[3] = makeU31(k[3], EK_D[3], iv[3]);
509         lfsrState[4] = makeU31(k[4], EK_D[4], iv[4]);
510         lfsrState[5] = makeU31(k[5], EK_D[5], iv[5]);
511         lfsrState[6] = makeU31(k[6], EK_D[6], iv[6]);
512         lfsrState[7] = makeU31(k[7], EK_D[7], iv[7]);
513         lfsrState[8] = makeU31(k[8], EK_D[8], iv[8]);
514         lfsrState[9] = makeU31(k[9], EK_D[9], iv[9]);
515         lfsrState[10] = makeU31(k[10], EK_D[10], iv[10]);
516         lfsrState[11] = makeU31(k[11], EK_D[11], iv[11]);
517         lfsrState[12] = makeU31(k[12], EK_D[12], iv[12]);
518         lfsrState[13] = makeU31(k[13], EK_D[13], iv[13]);
519         lfsrState[14] = makeU31(k[14], EK_D[14], iv[14]);
520         lfsrState[15] = makeU31(k[15], EK_D[15], iv[15]);
521     }
522 
523     /**
524      * Process key and IV.
525      *
526      * @param k  the key
527      * @param iv the IV
528      */
529     private void setKeyAndIV(final byte[] k,
530                              final byte[] iv) {
531         /* Initialise LFSR */
532         setKeyAndIV(lfsrState, k, iv);
533 
534         /* set F_R1 and F_R2 to zero */
535         fState[0] = 0;
536         fState[1] = 0;
537         int nCount = 32;
538         while (nCount > 0) {
539             bitReorganization();
540             final int w = f();
541             lfsrWithInitialisationMode(w >>> 1);
542             nCount--;
543         }
544         bitReorganization();
545         f(); // discard the output of F */
546         lfsrWithWorkMode();
547     }
548 
549     /**
550      * Create the next byte keyStream.
551      */
552     private void makeKeyStream() {
553         encode32be(makeKeyStreamWord(), keyStream, 0);
554     }
555 
556     /**
557      * Create the next keyStream word.
558      *
559      * @return the next word
560      */
561     public int makeKeyStreamWord() {
562         if (theIterations++ >= getMaxIterations()) {
563             throw new IllegalStateException("Too much data processed by singleKey/IV");
564         }
565         bitReorganization();
566         final int result = f() ^ brcState[3];
567         lfsrWithWorkMode();
568         return result;
569     }
570 
571     /**
572      * Create a copy of the engine.
573      *
574      * @return the copy
575      */
576     public GordianZuc128Engine copy() {
577         return new GordianZuc128Engine(this);
578     }
579 
580     /**
581      * Reset from saved engine state.
582      *
583      * @param pState teh state to restore
584      */
585     public void reset(final Memoable pState) {
586         final GordianZuc128Engine e = (GordianZuc128Engine) pState;
587         System.arraycopy(e.lfsrState, 0, lfsrState, 0, lfsrState.length);
588         System.arraycopy(e.fState, 0, fState, 0, fState.length);
589         System.arraycopy(e.brcState, 0, brcState, 0, brcState.length);
590         System.arraycopy(e.keyStream, 0, keyStream, 0, keyStream.length);
591         theIndex = e.theIndex;
592         theIterations = e.theIterations;
593         theResetState = e;
594     }
595 }