001package top.cenze.utils.crypt;
002
003import top.cenze.utils.crypt.sm.sm3.SM3;
004
005/**
006 * SM3国密加密解密工具
007 *
008 * @author chengze
009 * @date 2023-11-14 22:36
010 */
011public class SM3Util {
012
013    /** SM3值的长度 */
014    private static final int BYTE_LENGTH = 32;
015
016    /** SM3分组长度 */
017    private static final int BLOCK_LENGTH = 64;
018
019    /** 缓冲区长度 */
020    private static final int BUFFER_LENGTH = BLOCK_LENGTH * 1;
021
022    /** 缓冲区 */
023    private byte[] xBuf = new byte[BUFFER_LENGTH];
024
025    /** 缓冲区偏移量 */
026    private int xBufOff;
027
028    /** 初始向量 */
029    private byte[] V = SM3.iv.clone();
030
031    private int cntBlock = 0;
032
033    public SM3Util() {
034    }
035
036    public SM3Util(SM3Util t)
037    {
038        System.arraycopy(t.xBuf, 0, this.xBuf, 0, t.xBuf.length);
039        this.xBufOff = t.xBufOff;
040        System.arraycopy(t.V, 0, this.V, 0, t.V.length);
041    }
042
043    /**
044     * SM3结果输出
045     *
046     * @param out 保存SM3结构的缓冲区
047     * @param outOff 缓冲区偏移量
048     * @return
049     */
050    public int doFinal(byte[] out, int outOff)
051    {
052        byte[] tmp = doFinal();
053        System.arraycopy(tmp, 0, out, 0, tmp.length);
054        return BYTE_LENGTH;
055    }
056
057    public void reset()
058    {
059        xBufOff = 0;
060        cntBlock = 0;
061        V = SM3.iv.clone();
062    }
063
064    /**
065     * 明文输入
066     *
067     * @param in
068     *            明文输入缓冲区
069     * @param inOff
070     *            缓冲区偏移量
071     * @param len
072     *            明文长度
073     */
074    public void update(byte[] in, int inOff, int len)
075    {
076        int partLen = BUFFER_LENGTH - xBufOff;
077        int inputLen = len;
078        int dPos = inOff;
079        if (partLen < inputLen)
080        {
081            System.arraycopy(in, dPos, xBuf, xBufOff, partLen);
082            inputLen -= partLen;
083            dPos += partLen;
084            doUpdate();
085            while (inputLen > BUFFER_LENGTH)
086            {
087                System.arraycopy(in, dPos, xBuf, 0, BUFFER_LENGTH);
088                inputLen -= BUFFER_LENGTH;
089                dPos += BUFFER_LENGTH;
090                doUpdate();
091            }
092        }
093
094        System.arraycopy(in, dPos, xBuf, xBufOff, inputLen);
095        xBufOff += inputLen;
096    }
097
098    private void doUpdate()
099    {
100        byte[] B = new byte[BLOCK_LENGTH];
101        for (int i = 0; i < BUFFER_LENGTH; i += BLOCK_LENGTH)
102        {
103            System.arraycopy(xBuf, i, B, 0, B.length);
104            doHash(B);
105        }
106        xBufOff = 0;
107    }
108
109    private void doHash(byte[] B)
110    {
111        byte[] tmp = SM3.CF(V, B);
112        System.arraycopy(tmp, 0, V, 0, V.length);
113        cntBlock++;
114    }
115
116    private byte[] doFinal()
117    {
118        byte[] B = new byte[BLOCK_LENGTH];
119        byte[] buffer = new byte[xBufOff];
120        System.arraycopy(xBuf, 0, buffer, 0, buffer.length);
121        byte[] tmp = SM3.padding(buffer, cntBlock);
122        for (int i = 0; i < tmp.length; i += BLOCK_LENGTH)
123        {
124            System.arraycopy(tmp, i, B, 0, B.length);
125            doHash(B);
126        }
127        return V;
128    }
129
130    public void update(byte in)
131    {
132        byte[] buffer = new byte[] { in };
133        update(buffer, 0, 1);
134    }
135
136    public int getDigestSize()
137    {
138        return BYTE_LENGTH;
139    }
140
141//    public static void main(String[] args)
142//    {
143//        byte[] md = new byte[32];
144//        byte[] msg1 = "ererfeiisgod".getBytes();
145//        SM3Digest sm3 = new SM3Digest();
146//        sm3.update(msg1, 0, msg1.length);
147//        sm3.doFinal(md, 0);
148//        String s = new String(Hex.encode(md));
149//        System.out.println(s.toUpperCase());
150//    }
151}