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.util.Memoable;
20  
21  /**
22   * Zuc256Mac implementation.
23   * Based on http://www.is.cas.cn/ztzl2016/zouchongzhi/201801/W020180126529970733243.pdf
24   */
25  @SuppressWarnings("checkstyle:MagicNumber")
26  public class GordianZuc256Engine
27          extends GordianZuc128Engine {
28      /**
29       * the constants D.
30       */
31      private static final byte[] EK_D = {
32              0b0100010, 0b0101111, 0b0100100, 0b0101010, 0b1101101, 0b1000000, 0b1000000, 0b1000000,
33              0b1000000, 0b1000000, 0b1000000, 0b1000000, 0b1000000, 0b1010010, 0b0010000, 0b0110000
34      };
35  
36      /**
37       * the constants D for 32 bit Mac.
38       */
39      private static final byte[] EK_D32 = {
40              0b0100010, 0b0101111, 0b0100101, 0b0101010, 0b1101101, 0b1000000, 0b1000000, 0b1000000,
41              0b1000000, 0b1000000, 0b1000000, 0b1000000, 0b1000000, 0b1010010, 0b0010000, 0b0110000
42      };
43  
44      /**
45       * the constants D for 64 bit Mac.
46       */
47      private static final byte[] EK_D64 = {
48              0b0100011, 0b0101111, 0b0100100, 0b0101010, 0b1101101, 0b1000000, 0b1000000, 0b1000000,
49              0b1000000, 0b1000000, 0b1000000, 0b1000000, 0b1000000, 0b1010010, 0b0010000, 0b0110000
50      };
51  
52      /**
53       * the constants D for 128 bit Mac.
54       */
55      private static final byte[] EK_D128 = {
56              0b0100011, 0b0101111, 0b0100101, 0b0101010, 0b1101101, 0b1000000, 0b1000000, 0b1000000,
57              0b1000000, 0b1000000, 0b1000000, 0b1000000, 0b1000000, 0b1010010, 0b0010000, 0b0110000
58      };
59  
60      /**
61       * The selected D constants.
62       */
63      private byte[] theD;
64  
65      /**
66       * Constructor for streamCipher.
67       */
68      public GordianZuc256Engine() {
69          theD = EK_D;
70      }
71  
72      /**
73       * Constructor for Mac.
74       *
75       * @param pLength the Mac length
76       */
77      public GordianZuc256Engine(final int pLength) {
78          switch (pLength) {
79              case 32:
80                  theD = EK_D32;
81                  break;
82              case 64:
83                  theD = EK_D64;
84                  break;
85              case 128:
86                  theD = EK_D128;
87                  break;
88              default:
89                  throw new IllegalArgumentException("Unsupported length: " + pLength);
90          }
91      }
92  
93      /**
94       * Constructor for Memoable.
95       *
96       * @param pSource the source engine
97       */
98      private GordianZuc256Engine(final GordianZuc256Engine pSource) {
99          super(pSource);
100     }
101 
102     @Override
103     protected int getMaxIterations() {
104         return 625;
105     }
106 
107     @Override
108     public String getAlgorithmName() {
109         return "Zuc-256";
110     }
111 
112     /**
113      * Build a 31-bit integer from constituent parts.
114      *
115      * @param a part A
116      * @param b part B
117      * @param c part C
118      * @param d part D
119      * @return the built integer
120      */
121     private static int makeU31(final byte a, final byte b, final byte c, final byte d) {
122         return (((a & 0xFF) << 23) | ((b & 0xFF) << 16) | ((c & 0xFF) << 8) | (d & 0xFF));
123     }
124 
125     @Override
126     protected void setKeyAndIV(final int[] pLFSR,
127                                final byte[] k,
128                                final byte[] iv) {
129         /* Check lengths */
130         if (k == null || k.length != 32) {
131             throw new IllegalArgumentException("A key of 32 bytes is needed");
132         }
133         if (iv == null || iv.length != 25) {
134             throw new IllegalArgumentException("An IV of 25 bytes is needed");
135         }
136 
137         /* expand key and IV */
138         pLFSR[0] = makeU31(k[0], theD[0], k[21], k[16]);
139         pLFSR[1] = makeU31(k[1], theD[1], k[22], k[17]);
140         pLFSR[2] = makeU31(k[2], theD[2], k[23], k[18]);
141         pLFSR[3] = makeU31(k[3], theD[3], k[24], k[19]);
142         pLFSR[4] = makeU31(k[4], theD[4], k[25], k[20]);
143         pLFSR[5] = makeU31(iv[0], (byte) (theD[5] | (iv[17] & 0x3F)), k[5], k[26]);
144         pLFSR[6] = makeU31(iv[1], (byte) (theD[6] | (iv[18] & 0x3F)), k[6], k[27]);
145         pLFSR[7] = makeU31(iv[10], (byte) (theD[7] | (iv[19] & 0x3F)), k[7], iv[2]);
146         pLFSR[8] = makeU31(k[8], (byte) (theD[8] | (iv[20] & 0x3F)), iv[3], iv[11]);
147         pLFSR[9] = makeU31(k[9], (byte) (theD[9] | (iv[21] & 0x3F)), iv[12], iv[4]);
148         pLFSR[10] = makeU31(iv[5], (byte) (theD[10] | (iv[22] & 0x3F)), k[10], k[28]);
149         pLFSR[11] = makeU31(k[11], (byte) (theD[11] | (iv[23] & 0x3F)), iv[6], iv[13]);
150         pLFSR[12] = makeU31(k[12], (byte) (theD[12] | (iv[24] & 0x3F)), iv[7], iv[14]);
151         pLFSR[13] = makeU31(k[13], theD[13], iv[15], iv[8]);
152         pLFSR[14] = makeU31(k[14], (byte) (theD[14] | ((k[31] >>> 4) & 0xF)), iv[16], iv[9]);
153         pLFSR[15] = makeU31(k[15], (byte) (theD[15] | (k[31] & 0xF)), k[30], k[29]);
154     }
155 
156     @Override
157     public GordianZuc256Engine copy() {
158         return new GordianZuc256Engine(this);
159     }
160 
161     @Override
162     public void reset(final Memoable pState) {
163         final GordianZuc256Engine e = (GordianZuc256Engine) pState;
164         super.reset(pState);
165         theD = e.theD;
166     }
167 }