001package top.cenze.utils.crypt.sm.sm3;
002
003import top.cenze.utils.ConvertUtil;
004
005/**
006 * Created by $(USER) on $(DATE)
007 */
008public class SM3 {
009    public static final byte[] iv = { 0x73, (byte) 0x80, 0x16, 0x6f, 0x49,
010            0x14, (byte) 0xb2, (byte) 0xb9, 0x17, 0x24, 0x42, (byte) 0xd7,
011            (byte) 0xda, (byte) 0x8a, 0x06, 0x00, (byte) 0xa9, 0x6f, 0x30,
012            (byte) 0xbc, (byte) 0x16, 0x31, 0x38, (byte) 0xaa, (byte) 0xe3,
013            (byte) 0x8d, (byte) 0xee, 0x4d, (byte) 0xb0, (byte) 0xfb, 0x0e,
014            0x4e };
015
016    public static int[] Tj = new int[64];
017
018    static
019    {
020        for (int i = 0; i < 16; i++)
021        {
022            Tj[i] = 0x79cc4519;
023        }
024
025        for (int i = 16; i < 64; i++)
026        {
027            Tj[i] = 0x7a879d8a;
028        }
029    }
030
031    public static byte[] CF(byte[] V, byte[] B)
032    {
033        int[] v, b;
034        v = convert(V);
035        b = convert(B);
036        return convert(CF(v, b));
037    }
038
039    private static int[] convert(byte[] arr)
040    {
041        int[] out = new int[arr.length / 4];
042        byte[] tmp = new byte[4];
043        for (int i = 0; i < arr.length; i += 4)
044        {
045            System.arraycopy(arr, i, tmp, 0, 4);
046            out[i / 4] = bigEndianByteToInt(tmp);
047        }
048        return out;
049    }
050
051    private static byte[] convert(int[] arr)
052    {
053        byte[] out = new byte[arr.length * 4];
054        byte[] tmp = null;
055        for (int i = 0; i < arr.length; i++)
056        {
057            tmp = bigEndianIntToByte(arr[i]);
058            System.arraycopy(tmp, 0, out, i * 4, 4);
059        }
060        return out;
061    }
062
063    public static int[] CF(int[] V, int[] B)
064    {
065        int a, b, c, d, e, f, g, h;
066        int ss1, ss2, tt1, tt2;
067        a = V[0];
068        b = V[1];
069        c = V[2];
070        d = V[3];
071        e = V[4];
072        f = V[5];
073        g = V[6];
074        h = V[7];
075
076        int[][] arr = expand(B);
077        int[] w = arr[0];
078        int[] w1 = arr[1];
079
080        for (int j = 0; j < 64; j++)
081        {
082            ss1 = (bitCycleLeft(a, 12) + e + bitCycleLeft(Tj[j], j));
083            ss1 = bitCycleLeft(ss1, 7);
084            ss2 = ss1 ^ bitCycleLeft(a, 12);
085            tt1 = FFj(a, b, c, j) + d + ss2 + w1[j];
086            tt2 = GGj(e, f, g, j) + h + ss1 + w[j];
087            d = c;
088            c = bitCycleLeft(b, 9);
089            b = a;
090            a = tt1;
091            h = g;
092            g = bitCycleLeft(f, 19);
093            f = e;
094            e = P0(tt2);
095
096                            /*System.out.print(j+" ");
097                            System.out.print(Integer.toHexString(a)+" ");
098                            System.out.print(Integer.toHexString(b)+" ");
099                            System.out.print(Integer.toHexString(c)+" ");
100                            System.out.print(Integer.toHexString(d)+" ");
101                            System.out.print(Integer.toHexString(e)+" ");
102                            System.out.print(Integer.toHexString(f)+" ");
103                            System.out.print(Integer.toHexString(g)+" ");
104                            System.out.print(Integer.toHexString(h)+" ");
105                            System.out.println("");*/
106        }
107//                    System.out.println("");
108
109        int[] out = new int[8];
110        out[0] = a ^ V[0];
111        out[1] = b ^ V[1];
112        out[2] = c ^ V[2];
113        out[3] = d ^ V[3];
114        out[4] = e ^ V[4];
115        out[5] = f ^ V[5];
116        out[6] = g ^ V[6];
117        out[7] = h ^ V[7];
118
119        return out;
120    }
121
122    private static int[][] expand(int[] B)
123    {
124        int W[] = new int[68];
125        int W1[] = new int[64];
126        for (int i = 0; i < B.length; i++)
127        {
128            W[i] = B[i];
129        }
130
131        for (int i = 16; i < 68; i++)
132        {
133            W[i] = P1(W[i - 16] ^ W[i - 9] ^ bitCycleLeft(W[i - 3], 15))
134                    ^ bitCycleLeft(W[i - 13], 7) ^ W[i - 6];
135        }
136
137        for (int i = 0; i < 64; i++)
138        {
139            W1[i] = W[i] ^ W[i + 4];
140        }
141
142        int arr[][] = new int[][] { W, W1 };
143        return arr;
144    }
145
146    private static byte[] bigEndianIntToByte(int num)
147    {
148        return back(ConvertUtil.intToBytes(num));
149    }
150
151    private static int bigEndianByteToInt(byte[] bytes)
152    {
153        return ConvertUtil.byteToInt(back(bytes));
154    }
155
156    private static int FFj(int X, int Y, int Z, int j)
157    {
158        if (j >= 0 && j <= 15)
159        {
160            return FF1j(X, Y, Z);
161        }
162        else
163        {
164            return FF2j(X, Y, Z);
165        }
166    }
167
168    private static int GGj(int X, int Y, int Z, int j)
169    {
170        if (j >= 0 && j <= 15)
171        {
172            return GG1j(X, Y, Z);
173        }
174        else
175        {
176            return GG2j(X, Y, Z);
177        }
178    }
179
180    // 逻辑位运算函数
181    private static int FF1j(int X, int Y, int Z)
182    {
183        int tmp = X ^ Y ^ Z;
184        return tmp;
185    }
186
187    private static int FF2j(int X, int Y, int Z)
188    {
189        int tmp = ((X & Y) | (X & Z) | (Y & Z));
190        return tmp;
191    }
192
193    private static int GG1j(int X, int Y, int Z)
194    {
195        int tmp = X ^ Y ^ Z;
196        return tmp;
197    }
198
199    private static int GG2j(int X, int Y, int Z)
200    {
201        int tmp = (X & Y) | (~X & Z);
202        return tmp;
203    }
204
205    private static int P0(int X)
206    {
207        int y = rotateLeft(X, 9);
208        y = bitCycleLeft(X, 9);
209        int z = rotateLeft(X, 17);
210        z = bitCycleLeft(X, 17);
211        int t = X ^ y ^ z;
212        return t;
213    }
214
215    private static int P1(int X)
216    {
217        int t = X ^ bitCycleLeft(X, 15) ^ bitCycleLeft(X, 23);
218        return t;
219    }
220
221    /**
222     * 对最后一个分组字节数据padding
223     *
224     * @param in
225     * @param bLen
226     *            分组个数
227     * @return
228     */
229    public static byte[] padding(byte[] in, int bLen)
230    {
231        int k = 448 - (8 * in.length + 1) % 512;
232        if (k < 0)
233        {
234            k = 960 - (8 * in.length + 1) % 512;
235        }
236        k += 1;
237        byte[] padd = new byte[k / 8];
238        padd[0] = (byte) 0x80;
239        long n = in.length * 8 + bLen * 512;
240        byte[] out = new byte[in.length + k / 8 + 64 / 8];
241        int pos = 0;
242        System.arraycopy(in, 0, out, 0, in.length);
243        pos += in.length;
244        System.arraycopy(padd, 0, out, pos, padd.length);
245        pos += padd.length;
246        byte[] tmp = back(ConvertUtil.longToBytes(n));
247        System.arraycopy(tmp, 0, out, pos, tmp.length);
248        return out;
249    }
250
251    /**
252     * 字节数组逆序
253     *
254     * @param in
255     * @return
256     */
257    private static byte[] back(byte[] in)
258    {
259        byte[] out = new byte[in.length];
260        for (int i = 0; i < out.length; i++)
261        {
262            out[i] = in[out.length - i - 1];
263        }
264
265        return out;
266    }
267
268    public static int rotateLeft(int x, int n)
269    {
270        return (x << n) | (x >> (32 - n));
271    }
272
273    private static int bitCycleLeft(int n, int bitLen)
274    {
275        bitLen %= 32;
276        byte[] tmp = bigEndianIntToByte(n);
277        int byteLen = bitLen / 8;
278        int len = bitLen % 8;
279        if (byteLen > 0)
280        {
281            tmp = byteCycleLeft(tmp, byteLen);
282        }
283
284        if (len > 0)
285        {
286            tmp = bitSmall8CycleLeft(tmp, len);
287        }
288
289        return bigEndianByteToInt(tmp);
290    }
291
292    private static byte[] bitSmall8CycleLeft(byte[] in, int len)
293    {
294        byte[] tmp = new byte[in.length];
295        int t1, t2, t3;
296        for (int i = 0; i < tmp.length; i++)
297        {
298            t1 = (byte) ((in[i] & 0x000000ff) << len);
299            t2 = (byte) ((in[(i + 1) % tmp.length] & 0x000000ff) >> (8 - len));
300            t3 = (byte) (t1 | t2);
301            tmp[i] = (byte) t3;
302        }
303
304        return tmp;
305    }
306
307    private static byte[] byteCycleLeft(byte[] in, int byteLen)
308    {
309        byte[] tmp = new byte[in.length];
310        System.arraycopy(in, byteLen, tmp, 0, in.length - byteLen);
311        System.arraycopy(in, 0, tmp, in.length - byteLen, byteLen);
312        return tmp;
313    }
314
315//    public static void main(String[] args) {
316//        byte[] md = new byte[32];
317//        byte[] msg1 = "ererfeiisgod".getBytes();
318//        System.out.println(ConvertUtil.byteToHex(msg1));
319//        SM3Digest sm3 = new SM3Digest();
320//        sm3.update(msg1, 0, msg1.length);
321//        sm3.doFinal(md, 0);
322//        String s = new String(Hex.encode(md));
323//        System.out.println(s.toUpperCase());
324//    }
325}