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 ivParams)) {
187             newIV = ivParams.getIV();
188             myParams = ivParams.getParameters();
189         }
190         if (myParams instanceof KeyParameter keyParam) {
191             newKey = keyParam.getKey();
192         }
193 
194         /* Initialise engine and mark as initialised */
195         theIndex = 0;
196         theIterations = 0;
197         setKeyAndIV(newKey, newIV);
198 
199         /* Save reset state */
200         theResetState = copy();
201     }
202 
203     /**
204      * Obtain Max iterations.
205      *
206      * @return the maximum iterations
207      */
208     protected int getMaxIterations() {
209         return 2047;
210     }
211 
212     /**
213      * Obtain Algorithm Name.
214      *
215      * @return the name
216      */
217     public String getAlgorithmName() {
218         return "Zuc-128";
219     }
220 
221     /**
222      * Process bytes.
223      *
224      * @param in     the input buffer
225      * @param inOff  the starting offset in the input buffer
226      * @param len    the length of data in the input buffer
227      * @param out    the output buffer
228      * @param outOff the starting offset in the output buffer
229      * @return the number of bytes returned in the output buffer
230      */
231     public int processBytes(final byte[] in,
232                             final int inOff,
233                             final int len,
234                             final byte[] out,
235                             final int outOff) {
236         /* Check for errors */
237         if (theResetState == null) {
238             throw new IllegalStateException(getAlgorithmName() + " not initialised");
239         }
240         if ((inOff + len) > in.length) {
241             throw new DataLengthException("input buffer too short");
242         }
243         if ((outOff + len) > out.length) {
244             throw new OutputLengthException("output buffer too short");
245         }
246 
247         /* Loop through the input bytes */
248         for (int i = 0; i < len; i++) {
249             out[i + outOff] = returnByte(in[i + inOff]);
250         }
251         return len;
252     }
253 
254     /**
255      * Reset the engine.
256      */
257     public void reset() {
258         if (theResetState != null) {
259             reset(theResetState);
260         }
261     }
262 
263     /**
264      * Process single byte.
265      *
266      * @param in the input byte
267      * @return the output byte
268      */
269     public byte returnByte(final byte in) {
270         /* Make the keyStream if required */
271         if (theIndex == 0) {
272             makeKeyStream();
273         }
274 
275         /* Map the next byte and adjust index */
276         final byte out = (byte) (keyStream[theIndex] ^ in);
277         theIndex = (theIndex + 1) % Integer.BYTES;
278 
279         /* Return the mapped character */
280         return out;
281     }
282 
283     /**
284      * Encode a 32-bit value into a buffer (little-endian).
285      *
286      * @param val the value to encode
287      * @param buf the output buffer
288      * @param off the output offset
289      */
290     public static void encode32be(final int val, final byte[] buf, final int off) {
291         buf[off] = (byte) (val >> 24);
292         buf[off + 1] = (byte) (val >> 16);
293         buf[off + 2] = (byte) (val >> 8);
294         buf[off + 3] = (byte) val;
295     }
296 
297     /* ——————————————————————- */
298 
299     /**
300      * Modular add c = a + b mod (2^31 – 1).
301      *
302      * @param a value A
303      * @param b value B
304      * @return the result
305      */
306     private int addM(final int a, final int b) {
307         final int c = a + b;
308         return (c & 0x7FFFFFFF) + (c >>> 31);
309     }
310 
311     /**
312      * Multiply by power of two.
313      *
314      * @param x input value
315      * @param k the power of two
316      * @return the result
317      */
318     private static int mulByPow2(final int x, final int k) {
319         return ((((x) << k) | ((x) >>> (31 - k))) & 0x7FFFFFFF);
320     }
321 
322     /**
323      * LFSR with initialisation mode.
324      *
325      * @param u
326      */
327     private void lfsrWithInitialisationMode(final int u) {
328         int f = lfsrState[0];
329         int v = mulByPow2(lfsrState[0], 8);
330         f = addM(f, v);
331         v = mulByPow2(lfsrState[4], 20);
332         f = addM(f, v);
333         v = mulByPow2(lfsrState[10], 21);
334         f = addM(f, v);
335         v = mulByPow2(lfsrState[13], 17);
336         f = addM(f, v);
337         v = mulByPow2(lfsrState[15], 15);
338         f = addM(f, v);
339         f = addM(f, u);
340 
341         /* update the state */
342         lfsrState[0] = lfsrState[1];
343         lfsrState[1] = lfsrState[2];
344         lfsrState[2] = lfsrState[3];
345         lfsrState[3] = lfsrState[4];
346         lfsrState[4] = lfsrState[5];
347         lfsrState[5] = lfsrState[6];
348         lfsrState[6] = lfsrState[7];
349         lfsrState[7] = lfsrState[8];
350         lfsrState[8] = lfsrState[9];
351         lfsrState[9] = lfsrState[10];
352         lfsrState[10] = lfsrState[11];
353         lfsrState[11] = lfsrState[12];
354         lfsrState[12] = lfsrState[13];
355         lfsrState[13] = lfsrState[14];
356         lfsrState[14] = lfsrState[15];
357         lfsrState[15] = f;
358     }
359 
360     /**
361      * LFSR with work mode.
362      */
363     private void lfsrWithWorkMode() {
364         int f = lfsrState[0];
365         int v = mulByPow2(lfsrState[0], 8);
366         f = addM(f, v);
367         v = mulByPow2(lfsrState[4], 20);
368         f = addM(f, v);
369         v = mulByPow2(lfsrState[10], 21);
370         f = addM(f, v);
371         v = mulByPow2(lfsrState[13], 17);
372         f = addM(f, v);
373         v = mulByPow2(lfsrState[15], 15);
374         f = addM(f, v);
375 
376         /* update the state */
377         lfsrState[0] = lfsrState[1];
378         lfsrState[1] = lfsrState[2];
379         lfsrState[2] = lfsrState[3];
380         lfsrState[3] = lfsrState[4];
381         lfsrState[4] = lfsrState[5];
382         lfsrState[5] = lfsrState[6];
383         lfsrState[6] = lfsrState[7];
384         lfsrState[7] = lfsrState[8];
385         lfsrState[8] = lfsrState[9];
386         lfsrState[9] = lfsrState[10];
387         lfsrState[10] = lfsrState[11];
388         lfsrState[11] = lfsrState[12];
389         lfsrState[12] = lfsrState[13];
390         lfsrState[13] = lfsrState[14];
391         lfsrState[14] = lfsrState[15];
392         lfsrState[15] = f;
393     }
394 
395     /**
396      * BitReorganization.
397      */
398     private void bitReorganization() {
399         brcState[0] = ((lfsrState[15] & 0x7FFF8000) << 1) | (lfsrState[14] & 0xFFFF);
400         brcState[1] = ((lfsrState[11] & 0xFFFF) << 16) | (lfsrState[9] >>> 15);
401         brcState[2] = ((lfsrState[7] & 0xFFFF) << 16) | (lfsrState[5] >>> 15);
402         brcState[3] = ((lfsrState[2] & 0xFFFF) << 16) | (lfsrState[0] >>> 15);
403     }
404 
405     /**
406      * Rotate integer.
407      *
408      * @param a the integer
409      * @param k the shift
410      * @return the result
411      */
412     static int rot(final int a, final int k) {
413         return (((a) << k) | ((a) >>> (32 - k)));
414     }
415 
416     /**
417      * L1.
418      *
419      * @param x the input integer.
420      * @return the result
421      */
422     private static int l1(final int x) {
423         return (x ^ rot(x, 2) ^ rot(x, 10) ^ rot(x, 18) ^ rot(x, 24));
424     }
425 
426     /**
427      * L2.
428      *
429      * @param x the input integer.
430      * @return the result
431      */
432     private static int l2(final int x) {
433         return (x ^ rot(x, 8) ^ rot(x, 14) ^ rot(x, 22) ^ rot(x, 30));
434     }
435 
436     /**
437      * Build a 32-bit integer from constituent parts.
438      *
439      * @param a part A
440      * @param b part B
441      * @param c part C
442      * @param d part D
443      * @return the built integer
444      */
445     private static int makeU32(final byte a,
446                                final byte b,
447                                final byte c,
448                                final byte d) {
449         return (((a & 0xFF) << 24) | ((b & 0xFF) << 16) | ((c & 0xFF) << 8) | (d & 0xFF));
450     }
451 
452     /**
453      * F.
454      *
455      * @return the new state
456      */
457     int f() {
458         final int w = (brcState[0] ^ fState[0]) + fState[1];
459         final int w1 = fState[0] + brcState[1];
460         final int w2 = fState[1] ^ brcState[2];
461         final int u = l1((w1 << 16) | (w2 >>> 16));
462         final int v = l2((w2 << 16) | (w1 >>> 16));
463         fState[0] = makeU32(S0[u >>> 24], S1[(u >>> 16) & 0xFF],
464                 S0[(u >>> 8) & 0xFF], S1[u & 0xFF]);
465         fState[1] = makeU32(S0[v >>> 24], S1[(v >>> 16) & 0xFF],
466                 S0[(v >>> 8) & 0xFF], S1[v & 0xFF]);
467         return w;
468     }
469 
470     /**
471      * Build a 31-bit integer from constituent parts.
472      *
473      * @param a part A
474      * @param b part B
475      * @param c part C
476      * @return the built integer
477      */
478     private static int makeU31(final byte a,
479                                final short b,
480                                final byte c) {
481         return (((a & 0xFF) << 23) | ((b & 0xFFFF) << 8) | (c & 0xFF));
482     }
483 
484     /**
485      * Process key and IV into LFSR.
486      *
487      * @param pLFSR the LFSR
488      * @param k     the key
489      * @param iv    the iv
490      */
491     protected void setKeyAndIV(final int[] pLFSR,
492                                final byte[] k,
493                                final byte[] iv) {
494         /* Check lengths */
495         if (k == null || k.length != 16) {
496             throw new IllegalArgumentException("A key of 16 bytes is needed");
497         }
498         if (iv == null || iv.length != 16) {
499             throw new IllegalArgumentException("An IV of 16 bytes is needed");
500         }
501 
502         /* expand key */
503         lfsrState[0] = makeU31(k[0], EK_D[0], iv[0]);
504         lfsrState[1] = makeU31(k[1], EK_D[1], iv[1]);
505         lfsrState[2] = makeU31(k[2], EK_D[2], iv[2]);
506         lfsrState[3] = makeU31(k[3], EK_D[3], iv[3]);
507         lfsrState[4] = makeU31(k[4], EK_D[4], iv[4]);
508         lfsrState[5] = makeU31(k[5], EK_D[5], iv[5]);
509         lfsrState[6] = makeU31(k[6], EK_D[6], iv[6]);
510         lfsrState[7] = makeU31(k[7], EK_D[7], iv[7]);
511         lfsrState[8] = makeU31(k[8], EK_D[8], iv[8]);
512         lfsrState[9] = makeU31(k[9], EK_D[9], iv[9]);
513         lfsrState[10] = makeU31(k[10], EK_D[10], iv[10]);
514         lfsrState[11] = makeU31(k[11], EK_D[11], iv[11]);
515         lfsrState[12] = makeU31(k[12], EK_D[12], iv[12]);
516         lfsrState[13] = makeU31(k[13], EK_D[13], iv[13]);
517         lfsrState[14] = makeU31(k[14], EK_D[14], iv[14]);
518         lfsrState[15] = makeU31(k[15], EK_D[15], iv[15]);
519     }
520 
521     /**
522      * Process key and IV.
523      *
524      * @param k  the key
525      * @param iv the IV
526      */
527     private void setKeyAndIV(final byte[] k,
528                              final byte[] iv) {
529         /* Initialise LFSR */
530         setKeyAndIV(lfsrState, k, iv);
531 
532         /* set F_R1 and F_R2 to zero */
533         fState[0] = 0;
534         fState[1] = 0;
535         int nCount = 32;
536         while (nCount > 0) {
537             bitReorganization();
538             final int w = f();
539             lfsrWithInitialisationMode(w >>> 1);
540             nCount--;
541         }
542         bitReorganization();
543         f(); // discard the output of F */
544         lfsrWithWorkMode();
545     }
546 
547     /**
548      * Create the next byte keyStream.
549      */
550     private void makeKeyStream() {
551         encode32be(makeKeyStreamWord(), keyStream, 0);
552     }
553 
554     /**
555      * Create the next keyStream word.
556      *
557      * @return the next word
558      */
559     public int makeKeyStreamWord() {
560         if (theIterations++ >= getMaxIterations()) {
561             throw new IllegalStateException("Too much data processed by singleKey/IV");
562         }
563         bitReorganization();
564         final int result = f() ^ brcState[3];
565         lfsrWithWorkMode();
566         return result;
567     }
568 
569     /**
570      * Create a copy of the engine.
571      *
572      * @return the copy
573      */
574     public GordianZuc128Engine copy() {
575         return new GordianZuc128Engine(this);
576     }
577 
578     /**
579      * Reset from saved engine state.
580      *
581      * @param pState teh state to restore
582      */
583     public void reset(final Memoable pState) {
584         final GordianZuc128Engine e = (GordianZuc128Engine) pState;
585         System.arraycopy(e.lfsrState, 0, lfsrState, 0, lfsrState.length);
586         System.arraycopy(e.fState, 0, fState, 0, fState.length);
587         System.arraycopy(e.brcState, 0, brcState, 0, brcState.length);
588         System.arraycopy(e.keyStream, 0, keyStream, 0, keyStream.length);
589         theIndex = e.theIndex;
590         theIterations = e.theIterations;
591         theResetState = e;
592     }
593 }