001package top.cenze.utils.crypt;
002
003import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
004import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
005import org.bouncycastle.crypto.params.ECPublicKeyParameters;
006import org.bouncycastle.math.ec.ECPoint;
007import top.cenze.utils.ConvertUtil;
008import top.cenze.utils.crypt.sm.sm2.Cipher;
009import top.cenze.utils.crypt.sm.sm2.SM2;
010
011import java.io.IOException;
012import java.math.BigInteger;
013import java.util.HashMap;
014import java.util.Map;
015
016/**
017 * SM2国密加密解密工具
018 *
019 * @author chengze
020 * @date 2023-11-14 22:35
021 */
022public class SM2Util {
023
024    //生成随机秘钥对
025    public static Map generateKeyPair() {
026        Map<String, String> keyMap = new HashMap<String, String>(); // 存储公钥和私钥
027        SM2 sm2 = SM2.Instance();
028        AsymmetricCipherKeyPair key = sm2.ecc_key_pair_generator.generateKeyPair();
029        ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters) key.getPrivate();
030        ECPublicKeyParameters ecpub = (ECPublicKeyParameters) key.getPublic();
031        BigInteger privateKey = ecpriv.getD();
032        ECPoint publicKey = ecpub.getQ();
033        publicKey.getEncoded(true);
034        keyMap.put("privateKey", ConvertUtil.byteToHex(privateKey.toByteArray()));
035        keyMap.put("publicKey", ConvertUtil.byteToHex(publicKey.getEncoded(true)));
036//        System.out.println("公钥: " + ConvertUtil.byteToHex(publicKey.getEncoded()));
037//        System.out.println("私钥: " + ConvertUtil.byteToHex(privateKey.toByteArray()));
038
039        return keyMap;
040    }
041
042    //数据加密
043    public static String encrypt(byte[] publicKey, byte[] data) throws IOException
044    {
045        if (publicKey == null || publicKey.length == 0)
046        {
047            return null;
048        }
049
050        if (data == null || data.length == 0)
051        {
052            return null;
053        }
054
055        byte[] source = new byte[data.length];
056        System.arraycopy(data, 0, source, 0, data.length);
057
058        Cipher cipher = new Cipher();
059        SM2 sm2 = SM2.Instance();
060        ECPoint userKey = sm2.ecc_curve.decodePoint(publicKey);
061
062        ECPoint c1 = cipher.Init_enc(sm2, userKey);
063        cipher.Encrypt(source);
064        byte[] c3 = new byte[32];
065        cipher.Dofinal(c3);
066
067//      System.out.println("C1 " + Utils.byteToHex(c1.getEncoded()));
068//      System.out.println("C2 " + Utils.byteToHex(source));
069//      System.out.println("C3 " + Utils.byteToHex(c3));
070        //C1 C2 C3拼装成加密字串
071        return ConvertUtil.byteToHex(c1.getEncoded()) + ConvertUtil.byteToHex(source) + ConvertUtil.byteToHex(c3);
072
073    }
074
075    //数据解密
076    public static byte[] decrypt(byte[] privateKey, byte[] encryptedData) throws IOException
077    {
078        if (privateKey == null || privateKey.length == 0)
079        {
080            return null;
081        }
082
083        if (encryptedData == null || encryptedData.length == 0)
084        {
085            return null;
086        }
087        //加密字节数组转换为十六进制的字符串 长度变为encryptedData.length * 2
088        String data = ConvertUtil.byteToHex(encryptedData);
089        /***分解加密字串
090         * (C1 = C1标志位2位 + C1实体部分128位 = 130)
091         * (C3 = C3实体部分64位  = 64)
092         * (C2 = encryptedData.length * 2 - C1长度  - C2长度)
093         */
094        byte[] c1Bytes = ConvertUtil.hexToByte(data.substring(0,130));
095        int c2Len = encryptedData.length - 97;
096        byte[] c2 = ConvertUtil.hexToByte(data.substring(130,130 + 2 * c2Len));
097        byte[] c3 = ConvertUtil.hexToByte(data.substring(130 + 2 * c2Len,194 + 2 * c2Len));
098
099        SM2 sm2 = SM2.Instance();
100        BigInteger userD = new BigInteger(1, privateKey);
101
102        //通过C1实体字节来生成ECPoint
103        ECPoint c1 = sm2.ecc_curve.decodePoint(c1Bytes);
104        Cipher cipher = new Cipher();
105        cipher.Init_dec(userD, c1);
106        cipher.Decrypt(c2);
107        cipher.Dofinal(c3);
108
109        //返回解密结果
110        return c2;
111    }
112
113
114    //数据加密
115    public static String encrypt(String publicKeyStr, String dataStr) throws IOException
116    {
117        byte[] publicKey = ConvertUtil.hexToByte(publicKeyStr);
118        byte[] data = dataStr.getBytes("UTF-8");
119
120        byte[] source = new byte[data.length];
121        System.arraycopy(data, 0, source, 0, data.length);
122
123        Cipher cipher = new Cipher();
124        SM2 sm2 = SM2.Instance();
125        ECPoint userKey = sm2.ecc_curve.decodePoint(publicKey);
126
127        ECPoint c1 = cipher.Init_enc(sm2, userKey);
128        cipher.Encrypt(source);
129        byte[] c3 = new byte[32];
130        cipher.Dofinal(c3);
131
132        //C1 C2 C3拼装成加密字串
133        return ConvertUtil.byteToHex(c1.getEncoded()) + ConvertUtil.byteToHex(source) + ConvertUtil.byteToHex(c3);
134
135    }
136
137    //数据解密
138    public static byte[] decrypt(String privateKeyStr, String encryptedDataStr) throws IOException
139    {
140        byte[] privateKey = ConvertUtil.hexToByte(privateKeyStr);
141        byte[] encryptedData = ConvertUtil.hexToByte(encryptedDataStr);
142        //加密字节数组转换为十六进制的字符串 长度变为encryptedData.length * 2
143        String data = ConvertUtil.byteToHex(encryptedData);
144        /***分解加密字串
145         * (C1 = C1标志位2位 + C1实体部分128位 = 130)
146         * (C3 = C3实体部分64位  = 64)
147         * (C2 = encryptedData.length * 2 - C1长度  - C2长度)
148         */
149        byte[] c1Bytes = ConvertUtil.hexToByte(data.substring(0,130));
150        int c2Len = encryptedData.length - 97;
151        byte[] c2 = ConvertUtil.hexToByte(data.substring(130,130 + 2 * c2Len));
152        byte[] c3 = ConvertUtil.hexToByte(data.substring(130 + 2 * c2Len,194 + 2 * c2Len));
153
154        SM2 sm2 = SM2.Instance();
155        BigInteger userD = new BigInteger(1, privateKey);
156
157        //通过C1实体字节来生成ECPoint
158        ECPoint c1 = sm2.ecc_curve.decodePoint(c1Bytes);
159        Cipher cipher = new Cipher();
160        cipher.Init_dec(userD, c1);
161        cipher.Decrypt(c2);
162        cipher.Dofinal(c3);
163
164        //返回解密结果
165        return c2;
166    }
167
168//    public static void main(String[] args){
169//        generateKeyPair();
170//        String publicKey = "04CF0565941EAE46B935057343EC7CD51F6BB4DCEC10238667625ECE3BD516F2323C781B0A5B97C123748353ACA81221C974C662A2C1C320F7532DDD2D3ECC106F";
171//        String privateKey = "00AA40384C9AB7CC44E8B2481737F98C88A8C8474497DA0CFE58B625BB3E79F97B";
172//        String ss = "oahgiooahgiouaoi弄我阿济格hi噢阿济格hi噢hi";
173//
174//        try {
175//            String dataEn = encrypt(publicKey, ss);
176//            System.out.println(dataEn);
177//
178//            String dataDe = new String(decrypt(privateKey,dataEn));
179//            System.out.println(dataDe);
180//        }catch (Exception e){
181//            e.printStackTrace();
182//        }
183//    }
184}