zoukankan      html  css  js  c++  java
  • Java国密相关算法(bouncycastle)

    公用类算法:

    PCIKeyPair.java

    /**
     * @Author: dzy
     * @Date: 2018/9/27 14:18
     * @Describe: 公私钥对
     */
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class PCIKeyPair {
    
        private String priKey;      //私钥
        private String pubKey;      //公钥
    
    }

    CommonUtils.java

    import org.apache.commons.lang3.StringUtils;
    
    import java.io.UnsupportedEncodingException;
    import java.nio.ByteBuffer;
    import java.nio.ByteOrder;
    import java.text.SimpleDateFormat;
    import java.util.Calendar;
    import java.util.Date;
    
    /**
     * @ClassName: CommonUtils
     * @Description: 通用工具类
     * @since: 0.0.1
     * @author: dzy
     * @date: 2017年2月22日 上午11:46:44
     */
    public class CommonUtils {
    
    
        /**
         * @param date    日期
         * @param pattern 模式 如:yyyyMMdd等
         * @return
         * @Title: formatDate
         * @Description: 格式化日期
         * @since: 0.0.1
         */
        public static String formatDate(Date date, String pattern) {
            SimpleDateFormat formatter = new SimpleDateFormat(pattern);
            return formatter.format(date);
        }
    
        /**
         * @param strDate String类型日期
         * @param pattern 日期显示模式
         * @return
         * @Title: parseDate
         * @Description: 将String日期转换为Date类型日期
         * @since: 0.0.1
         */
        public static Date parseDate(String strDate, String pattern) {
            SimpleDateFormat formatter = null;
            if (StringUtils.isBlank(strDate)) {
                return null;
            }
            formatter = new SimpleDateFormat(pattern);
            try {
                return formatter.parse(strDate);
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
    
        /**
         * @param date   操作前的日期
         * @param field  日期的部分如:年,月,日
         * @param amount 增加或减少的值(负数表示减少)
         * @return
         * @Title: dateAdd
         * @Description: 日期的加减操作
         * @since: 0.0.1
         */
        public static Date dateAdd(Date date, int field, int amount) {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(date);
            calendar.add(field, amount);
            return calendar.getTime();
        }
    
        /**
         * @param source 源字符串
         * @param offset 填充开始的位置, 0-在左边, source.getBytes().length 在右边, 如果有中文时需小心位置
         * @param c      用于填充的字符
         * @param length 最后字符串的字节长度
         * @return
         * @Title: fill
         * @Description: 填充字符串, 长度是按字节计算, 不是字符
         * @since: 0.0.1
         */
        public static String fill(String source, int offset, char c, int length) throws UnsupportedEncodingException {
            if (null == source) {
                source = "";
            }
            if (source.getBytes(CustomConstants.CHARSET_UTF8).length == length) {
                return source;
            }
            byte[] buf = new byte[length];
            byte[] src = source.getBytes(CustomConstants.CHARSET_UTF8);
            if (src.length > length) {
                System.arraycopy(src, src.length - length, buf, 0, length);
                return new String(buf, CustomConstants.CHARSET_UTF8);
            }
            if (offset > src.length) {
                offset = src.length;
            } else if (offset < 0) {
                offset = 0;
            }
            int n = length - src.length;
    
            System.arraycopy(src, 0, buf, 0, offset);
            for (int i = 0; i < n; i++) {
                buf[i + offset] = (byte) c;
            }
            System.arraycopy(src, offset, buf, offset + n, src.length - offset);
            return new String(buf, CustomConstants.CHARSET_UTF8);
        }
    
        /**
         * @param original 原字符串
         * @param offset   填充开始的位置, 0-在左边, original.getBytes().length 在右边, 如果有中文时需小心位置
         * @param length   替换的字节数
         * @param c        用于替换的字符
         * @return
         * @Title: replace
         * @Description: 替换字符串, 长度是按字节计算, 不是字符
         * @since: 0.0.1
         */
        public static String replace(String original, int offset, int length, char c) throws UnsupportedEncodingException {
            if (original == null) {
                original = "";
            }
            if (original.getBytes(CustomConstants.CHARSET_UTF8).length <= offset) {
                return original;
            }
            if (original.getBytes(CustomConstants.CHARSET_UTF8).length < offset + length) {
                length = original.getBytes(CustomConstants.CHARSET_UTF8).length - offset;
            }
            byte[] buf = new byte[original.length()];
            byte[] src = original.getBytes(CustomConstants.CHARSET_UTF8);
            System.arraycopy(src, 0, buf, 0, offset);
    
            for (int i = offset; i < offset + length; i++) {
                buf[i] = (byte) c;
            }
            System.arraycopy(src, offset + length, buf, offset + length, src.length - offset - length);
            return new String(buf, CustomConstants.CHARSET_UTF8);
        }
    
        /**
         * @param s 16进制字符串
         * @return
         * @Title: hexToByte
         * @Description: 16进制字符串转字节数组
         * @since: 0.0.1
         */
        public static byte[] hexToByte(String s) {
            byte[] result = null;
            try {
                int i = s.length();
    //            if (i % 2 == 1) {
    //                throw new Exception("字符串长度不是偶数.");
    //            }
                if (i % 2 != 0) {
                    throw new Exception("字符串长度不是偶数.");
                }
                result = new byte[i / 2];
                for (int j = 0; j < result.length; j++) {
                    result[j] = (byte) Integer.parseInt(s.substring(j * 2, j * 2 + 2), 16);
                }
            } catch (Exception e) {
                result = null;
                e.printStackTrace();
    //            log.error("16进制字符串转字节数组时出现异常:", e);
            }
            return result;
        }
    
        /**
         * @param bytes 字节数组
         * @return
         * @Title: byte2hexString
         * @Description: 字节数组转换为16进制字符串    //0x33 0xD2 0x00 0x46 转换为 "33d20046" 转换和打印报文用
         * @since: 0.0.1
         */
        public static String byte2hexString(byte[] bytes) {
            StringBuffer buf = new StringBuffer(bytes.length * 2);
            for (int i = 0; i < bytes.length; i++) {
                if (((int) bytes[i] & 0xff) < 0x10) {
                    buf.append("0");
                }
                buf.append(Long.toString((int) bytes[i] & 0xff, 16));
            }
            return buf.toString().toUpperCase();
        }
    
        /**
         * @param hexString 16进制字符串    如:"33d20046" 转换为 0x33 0xD2 0x00 0x46
         * @return
         * @Title: hexString2byte
         * @Description: 16进制字符串转字节数组
         * @since: 0.0.1
         */
        public static byte[] hexString2byte(String hexString) {
            if (null == hexString || hexString.length() % 2 != 0 || hexString.contains("null")) {
                return null;
            }
            byte[] bytes = new byte[hexString.length() / 2];
            for (int i = 0; i < hexString.length(); i += 2) {
                bytes[i / 2] = (byte) (Integer.parseInt(hexString.substring(i, i + 2), 16) & 0xff);
            }
            return bytes;
        }
    
        /**
         * @param i 需要转的int类型数字
         * @return
         * @Title: byte1ToBcd2
         * @Description: int类型转BCD码
         * @since: 0.0.1
         */
        public static String byte1ToBcd2(int i) {
    //        return (new Integer(i / 16).toString() + (new Integer(i % 16)).toString());
            return Integer.toString(i / 16) + Integer.toString(i % 16);
        }
    
        /**
         * @param b 字节数组
         * @return
         * @Title: byteToHex2
         * @Description: 字节数组转换为16进制字符串        For example, byte[] {0x01,0x23,0x45,0x67,0x89,0xAB,0xCD,0xEF} will be changed to String "0123456789ABCDEF"
         * @since: 0.0.1
         */
        public static String byteToHex2(byte[] b) {
            StringBuffer result = new StringBuffer();
            String tmp = "";
    
            for (int i = 0; i < b.length; i++) {
                tmp = Integer.toHexString(b[i] & 0xff);
                if (tmp.length() == 1) {
                    result.append("0" + tmp);
                } else {
                    result.append(tmp);
                }
            }
            return result.toString().toUpperCase();
        }
    
        /**
         * @param num 数字
         * @param len 字节数组长度
         * @return
         * @Title: intToHexBytes
         * @Description: int类型转16进制字节数组
         */
        public static byte[] intToHexBytes(int num, int len) {
            byte[] bytes = null;
            String hexString = Integer.toHexString(num);
            if (len > 0) {
                int length = len * 2;
                hexString = CustomStringUtils.leftFill(hexString, '0', length);
                bytes = CommonUtils.hexString2byte(hexString);
            }
            return bytes;
        }
    
        /*public static String byteToHex3(byte[] b) {
            String result = "";
            String tmp = "";
    
            for (int n = 0; n < b.length; n++) {
                tmp = (java.lang.Integer.toHexString(b[n] & 0XFF));
                if (tmp.length() == 1) {
                    result = result + "0" + tmp;
                } else {
                    result = result + tmp;
                }
                if (n < b.length - 1) {
                    result = result + "";
                }
            }
            return result.toUpperCase();
        }*/
    
        /**
         * @param str 需要转换编码的字符串
         * @return
         * @Title: iso2Gbk
         * @Description: 将ISO-8859-1编码的字符串转成GBK编码的字符串
         * @since: 0.0.1
         */
        public static String iso2Gbk(String str) {
            if (null == str) {
                return str;
            }
            try {
                return new String(str.getBytes("ISO-8859-1"), "GBK");
            } catch (UnsupportedEncodingException e) {
    //            log.error("不支持的编码异常:", e);
                e.printStackTrace();
                return str;
            }
        }
    
    //    /**
    //     * @param message
    //     * @return
    //     * @Title: getSubElement
    //     * @Description: 分解各子域到HashMap
    //     * @since: 0.0.1
    //     */
    //    public static Map<String, String> getSubElement(byte[] message) {
    //        Map<String, String> map = new HashMap<String, String>();
    //        String key = null;
    //        String value = null;
    //        int len = 0;
    //        int idx = 0;
    //        while (idx < message.length) {
    //            key = new String(message, idx, 2);
    //            idx += 2;    //取了SE id 移2位
    //            len = Integer.parseInt(new String(message, idx, 2));
    //            idx += 2;    //取了SE id的内容长度  移2位
    //            value = new String(message, idx, len);
    //            map.put(key, value);
    //            idx += len;
    //        }
    //        return map;
    //    }
    
        //byte数组转成long
    
        /**
         * @param b 将字节数组转long类型 位置为小端
         * @return
         */
        public static long byteToLong(byte[] b) {
            long s = 0;
            long s0 = b[0] & 0xff;// 最低位
            long s1 = b[1] & 0xff;
            long s2 = b[2] & 0xff;
            long s3 = b[3] & 0xff;
            long s4 = b[4] & 0xff;// 最低位
            long s5 = b[5] & 0xff;
            long s6 = b[6] & 0xff;
            long s7 = b[7] & 0xff;
    
            // s0不变
            s1 <<= 8;
            s2 <<= 16;
            s3 <<= 24;
            s4 <<= 8 * 4;
            s5 <<= 8 * 5;
            s6 <<= 8 * 6;
            s7 <<= 8 * 7;
            s = s0 | s1 | s2 | s3 | s4 | s5 | s6 | s7;
            return s;
        }
    
        /**
         * @param b 将字节数组转int类型     位置为小端
         * @return
         */
        public static int byteToInt(byte[] b) {
            int s = 0;
            int s0 = b[0] & 0xff;// 最低位
            int s1 = b[1] & 0xff;
            int s2 = b[2] & 0xff;
            int s3 = b[3] & 0xff;
    
            // s0不变
            s1 <<= 8;
            s2 <<= 16;
            s3 <<= 24;
    
            s = s0 | s1 | s2 | s3;
            return s;
        }
    
        /**
         * int类型转换小端的byte数组
         * @param i
         * @return
         */
        public static byte[] intToLittleBytes(int i) {
            ByteBuffer byteBuffer = ByteBuffer.allocate(4);
            byteBuffer.order(ByteOrder.LITTLE_ENDIAN);
            byteBuffer.asIntBuffer().put(i);
            byte[] littleBytes = byteBuffer.array();
            return littleBytes;
        }
    
        /**
         * 将一个字节转成10进制
         * @param b
         * @return
         */
        public static int byteToInt(byte b) {
            int value = b & 0xff;
            return value;
        }
    
        /**
         *  字节数组合并
         * @param bt1   字节数组bt1
         * @param bt2   字节数组bt2
         * @return
         */
        public static byte[] byteMerger(byte[] bt1, byte[] bt2){
            byte[] bt3 = new byte[bt1.length+bt2.length];
            System.arraycopy(bt1, 0, bt3, 0, bt1.length);
            System.arraycopy(bt2, 0, bt3, bt1.length, bt2.length);
            return bt3;
        }
    
    }

    SM2算法:

    package com.pcidata.common.tools.encrypt;
    
    import com.pcidata.common.tools.CommonUtils;
    import com.pcidata.common.tools.CustomStringUtils;
    import com.pcidata.modules.key.modelvo.response.PCIKeyPair;
    import lombok.extern.slf4j.Slf4j;
    import org.bouncycastle.asn1.gm.GMNamedCurves;
    import org.bouncycastle.asn1.x9.X9ECParameters;
    import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
    import org.bouncycastle.crypto.engines.SM2Engine;
    import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
    import org.bouncycastle.crypto.params.*;
    import org.bouncycastle.crypto.signers.SM2Signer;
    import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
    import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
    import org.bouncycastle.jce.spec.ECParameterSpec;
    import org.bouncycastle.math.ec.ECPoint;
    import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
    import org.bouncycastle.util.Strings;
    import org.bouncycastle.util.encoders.Hex;
    
    import java.math.BigInteger;
    import java.security.NoSuchAlgorithmException;
    import java.security.PrivateKey;
    import java.security.PublicKey;
    import java.security.SecureRandom;
    
    /**
     * @Author: dzy
     * @Date: 2018/9/28 15:53
     * @Describe: SM2工具类
     */
    @Slf4j
    public class SM2Util {
    
        /**
         * 生成SM2公私钥对
         * @return
         */
        private static AsymmetricCipherKeyPair genKeyPair0() {
            //获取一条SM2曲线参数
            X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
    
            //构造domain参数
            ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(),
                    sm2ECParameters.getG(), sm2ECParameters.getN());
    
            //1.创建密钥生成器
            ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator();
    
            //2.初始化生成器,带上随机数
            try {
                keyPairGenerator.init(new ECKeyGenerationParameters(domainParameters, SecureRandom.getInstance("SHA1PRNG")));
            } catch (NoSuchAlgorithmException e) {
                log.error("生成公私钥对时出现异常:", e);
    //            e.printStackTrace();
            }
    
            //3.生成密钥对
            AsymmetricCipherKeyPair asymmetricCipherKeyPair = keyPairGenerator.generateKeyPair();
            return asymmetricCipherKeyPair;
        }
    
        /**
         * 生成公私钥对(默认压缩公钥)
         * @return
         */
        public static PCIKeyPair genKeyPair() {
            return genKeyPair(true);
        }
    
        /**
         * 生成公私钥对
         * @param compressedPubKey  是否压缩公钥
         * @return
         */
        public static PCIKeyPair genKeyPair(boolean compressedPubKey) {
            AsymmetricCipherKeyPair asymmetricCipherKeyPair = genKeyPair0();
    
            //提取公钥点
            ECPoint ecPoint = ((ECPublicKeyParameters) asymmetricCipherKeyPair.getPublic()).getQ();
            //公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥,04的时候,可以去掉前面的04
            String pubKey = Hex.toHexString(ecPoint.getEncoded(compressedPubKey));
    
            BigInteger privatekey = ((ECPrivateKeyParameters) asymmetricCipherKeyPair.getPrivate()).getD();
            String priKey = privatekey.toString(16);
    
            PCIKeyPair keyPair = new PCIKeyPair(priKey, pubKey);
            return keyPair;
        }
    
        /**
         * 私钥签名
         * @param privateKey    私钥
         * @param content       待签名内容
         * @return
         */
        public static String sign(String privateKey, String content) {
            //待签名内容转为字节数组
            byte[] message = Hex.decode(content);
    
            //获取一条SM2曲线参数
            X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
            //构造domain参数
            ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(),
                    sm2ECParameters.getG(), sm2ECParameters.getN());
    
            BigInteger privateKeyD = new BigInteger(privateKey, 16);
            ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(privateKeyD, domainParameters);
    
            //创建签名实例
            SM2Signer sm2Signer = new SM2Signer();
    
            //初始化签名实例,带上ID,国密的要求,ID默认值:1234567812345678
            try {
                sm2Signer.init(true, new ParametersWithID(new ParametersWithRandom(privateKeyParameters, SecureRandom.getInstance("SHA1PRNG")), Strings.toByteArray("1234567812345678")));
            } catch (NoSuchAlgorithmException e) {
                log.error("签名时出现异常:", e);
            }
    
            //生成签名,签名分为两部分r和s,分别对应索引0和1的数组
            BigInteger[] bigIntegers = sm2Signer.generateSignature(message);
    
            byte[] rBytes = modifyRSFixedBytes(bigIntegers[0].toByteArray());
            byte[] sBytes = modifyRSFixedBytes(bigIntegers[1].toByteArray());
    
            byte[] signBytes = ByteUtils.concatenate(rBytes, sBytes);
            String sign = Hex.toHexString(signBytes);
    
            return sign;
        }
    
        /**
         * 将R或者S修正为固定字节数
         * @param rs
         * @return
         */
        private static byte[] modifyRSFixedBytes(byte[] rs) {
            int length = rs.length;
            int fixedLength = 32;
            byte[] result = new byte[fixedLength];
            if (length < 32) {
                System.arraycopy(rs, 0, result, fixedLength - length, length);
            } else {
                System.arraycopy(rs, length - fixedLength, result, 0, fixedLength);
            }
            return result;
        }
    
        /**
         * 验证签名
         * @param publicKey     公钥
         * @param content       待签名内容
         * @param sign          签名值
         * @return
         */
        public static boolean verify(String publicKey, String content, String sign) {
            //待签名内容
            byte[] message = Hex.decode(content);
            byte[] signData = Hex.decode(sign);
    
            // 获取一条SM2曲线参数
            X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
            // 构造domain参数
            ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(),
                    sm2ECParameters.getG(),
                    sm2ECParameters.getN());
            //提取公钥点
            ECPoint pukPoint = sm2ECParameters.getCurve().decodePoint(CommonUtils.hexString2byte(publicKey));
            // 公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥, 04的时候,可以去掉前面的04
            ECPublicKeyParameters publicKeyParameters = new ECPublicKeyParameters(pukPoint, domainParameters);
    
            //获取签名
            BigInteger R = null;
            BigInteger S = null;
            byte[] rBy = new byte[33];
            System.arraycopy(signData, 0, rBy, 1, 32);
            rBy[0] = 0x00;
            byte[] sBy = new byte[33];
            System.arraycopy(signData, 32, sBy, 1, 32);
            sBy[0] = 0x00;
            R = new BigInteger(rBy);
            S = new BigInteger(sBy);
    
            //创建签名实例
            SM2Signer sm2Signer = new SM2Signer();
            ParametersWithID parametersWithID = new ParametersWithID(publicKeyParameters, Strings.toByteArray("1234567812345678"));
            sm2Signer.init(false, parametersWithID);
    
            //验证签名结果
            boolean verify = sm2Signer.verifySignature(message, R, S);
            return verify;
        }
    
        /**
         * SM2加密算法
         * @param publicKey     公钥
         * @param data          数据
         * @return
         */
        public static String encrypt(String publicKey, String data){
            // 获取一条SM2曲线参数
            X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
            // 构造domain参数
            ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(),
                    sm2ECParameters.getG(),
                    sm2ECParameters.getN());
            //提取公钥点
            ECPoint pukPoint = sm2ECParameters.getCurve().decodePoint(CommonUtils.hexString2byte(publicKey));
            // 公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥, 04的时候,可以去掉前面的04
            ECPublicKeyParameters publicKeyParameters = new ECPublicKeyParameters(pukPoint, domainParameters);
    
            SM2Engine sm2Engine = new SM2Engine();
            sm2Engine.init(true, new ParametersWithRandom(publicKeyParameters, new SecureRandom()));
    
            byte[] arrayOfBytes = null;
            try {
                byte[] in = data.getBytes("utf-8");
                arrayOfBytes = sm2Engine.processBlock(in, 0, in.length);
            } catch (Exception e) {
                log.error("SM2加密时出现异常:", e);
            }
            return Hex.toHexString(arrayOfBytes);
        }
    
        /**
         * SM2加密算法
         * @param publicKey     公钥
         * @param data          明文数据
         * @return
         */
        public static String encrypt(PublicKey publicKey, String data) {
    
            ECPublicKeyParameters ecPublicKeyParameters = null;
            if (publicKey instanceof BCECPublicKey) {
                BCECPublicKey bcecPublicKey = (BCECPublicKey) publicKey;
                ECParameterSpec ecParameterSpec = bcecPublicKey.getParameters();
                ECDomainParameters ecDomainParameters = new ECDomainParameters(ecParameterSpec.getCurve(),
                        ecParameterSpec.getG(), ecParameterSpec.getN());
                ecPublicKeyParameters = new ECPublicKeyParameters(bcecPublicKey.getQ(), ecDomainParameters);
            }
    
            SM2Engine sm2Engine = new SM2Engine();
            sm2Engine.init(true, new ParametersWithRandom(ecPublicKeyParameters, new SecureRandom()));
    
            byte[] arrayOfBytes = null;
            try {
                byte[] in = data.getBytes("utf-8");
                arrayOfBytes = sm2Engine.processBlock(in,0, in.length);
            } catch (Exception e) {
                log.error("SM2加密时出现异常:", e);
            }
            return Hex.toHexString(arrayOfBytes);
        }
    
        /**
         * SM2解密算法
         * @param privateKey    私钥
         * @param cipherData    密文数据
         * @return
         */
        public static String decrypt(String privateKey, String cipherData) {
            byte[] cipherDataByte = Hex.decode(cipherData);
    
            //获取一条SM2曲线参数
            X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
            //构造domain参数
            ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(),
                    sm2ECParameters.getG(), sm2ECParameters.getN());
    
            BigInteger privateKeyD = new BigInteger(privateKey, 16);
            ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(privateKeyD, domainParameters);
    
            SM2Engine sm2Engine = new SM2Engine();
            sm2Engine.init(false, privateKeyParameters);
    
            String result = null;
            try {
                byte[] arrayOfBytes = sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length);
                return new String(arrayOfBytes, "utf-8");
            } catch (Exception e) {
                log.error("SM2解密时出现异常:", e);
            }
            return result;
    
        }
    
        /**
         * SM2解密算法
         * @param privateKey        私钥
         * @param cipherData        密文数据
         * @return
         */
        public static String decrypt(PrivateKey privateKey, String cipherData) {
            byte[] cipherDataByte = Hex.decode(cipherData);
    
            BCECPrivateKey bcecPrivateKey = (BCECPrivateKey) privateKey;
            ECParameterSpec ecParameterSpec = bcecPrivateKey.getParameters();
    
            ECDomainParameters ecDomainParameters = new ECDomainParameters(ecParameterSpec.getCurve(),
                    ecParameterSpec.getG(), ecParameterSpec.getN());
    
            ECPrivateKeyParameters ecPrivateKeyParameters = new ECPrivateKeyParameters(bcecPrivateKey.getD(),
                    ecDomainParameters);
    
            SM2Engine sm2Engine = new SM2Engine();
            sm2Engine.init(false, ecPrivateKeyParameters);
    
            String result = null;
            try {
                byte[] arrayOfBytes = sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length);
                return new String(arrayOfBytes, "utf-8");
            } catch (Exception e) {
                log.error("SM2解密时出现异常:", e);
            }
            return result;
        }
    
        /**
         * 将未压缩公钥压缩成压缩公钥
         * @param pubKey    未压缩公钥(16进制,不要带头部04)
         * @return
         */
        public static String compressPubKey(String pubKey) {
            pubKey = CustomStringUtils.append("04", pubKey);    //将未压缩公钥加上未压缩标识.
            // 获取一条SM2曲线参数
            X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
            // 构造domain参数
            ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(),
                    sm2ECParameters.getG(),
                    sm2ECParameters.getN());
            //提取公钥点
            ECPoint pukPoint = sm2ECParameters.getCurve().decodePoint(CommonUtils.hexString2byte(pubKey));
            // 公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥, 04的时候,可以去掉前面的04
    //        ECPublicKeyParameters publicKeyParameters = new ECPublicKeyParameters(pukPoint, domainParameters);
    
            String compressPubKey = Hex.toHexString(pukPoint.getEncoded(Boolean.TRUE));
    
            return compressPubKey;
        }
    
        /**
         * 将压缩的公钥解压为非压缩公钥
         * @param compressKey   压缩公钥
         * @return
         */
        public static String unCompressPubKey(String compressKey) {
            // 获取一条SM2曲线参数
            X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");
            // 构造domain参数
            ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(),
                    sm2ECParameters.getG(),
                    sm2ECParameters.getN());
            //提取公钥点
            ECPoint pukPoint = sm2ECParameters.getCurve().decodePoint(CommonUtils.hexString2byte(compressKey));
            // 公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥, 04的时候,可以去掉前面的04
    //        ECPublicKeyParameters publicKeyParameters = new ECPublicKeyParameters(pukPoint, domainParameters);
    
            String pubKey = Hex.toHexString(pukPoint.getEncoded(Boolean.FALSE));
            pubKey = pubKey.substring(2);       //去掉前面的04   (04的时候,可以去掉前面的04)
    
            return pubKey;
        }
    
    }

    SM3算法:

    import lombok.extern.slf4j.Slf4j;
    import org.bouncycastle.crypto.digests.SM3Digest;
    import org.bouncycastle.crypto.macs.HMac;
    import org.bouncycastle.crypto.params.KeyParameter;
    import org.bouncycastle.util.encoders.Hex;
    
    import java.security.MessageDigest;
    
    /**
     * @Author: dzy
     * @Date: 2018/10/19 16:36
     * @Describe: SM3工具类(杂凑算法-hash算法)
     */
    @Slf4j
    public class SM3Util {
    
        /**
         * 16进制字符串SM3生成HASH签名值算法
         * @param hexString     16进制字符串
         * @return
         */
        public static String hexEncrypt(String hexString) {
            byte[] srcData = Hex.decode(hexString);
            byte[] encrypt = encrypt(srcData);
            String cipherStr  = Hex.toHexString(encrypt);
            return cipherStr;
        }
    
        /**
         * 16进制字符串SM3生成HASH签名值算法
         * @param hexKey        16进制密钥
         * @param hexString     16进制字符串
         * @return
         */
        public static String hexEncrypt(String hexKey, String hexString) {
            byte[] key = Hex.decode(hexKey);
            byte[] srcData = Hex.decode(hexString);
            byte[] encrypt = encrypt(key, srcData);
            String cipherStr  = Hex.toHexString(encrypt);
            return cipherStr;
        }
    
        /**
         * 普通文本SM3生成HASH签名算法
         * @param plain     待签名数据
         * @return
         */
        public static String plainEncrypt(String plain) {
            // 将返回的hash值转换成16进制字符串
            String cipherStr = null;
            try {
                //将字符串转换成byte数组
                byte[] srcData = plain.getBytes(CustomConstants.CHARSET_UTF8);
                //调用encrypt计算hash
                byte[] encrypt = encrypt(srcData);
                //将返回的hash值转换成16进制字符串
                cipherStr = Hex.toHexString(encrypt);
            } catch (Exception e) {
                log.error("将字符串转换为字节时出现异常:", e);
            }
            return cipherStr;
        }
    
        /**
         * 普通文本SM3生成HASH签名算法
         * @param hexKey        密钥
         * @param plain         待签名数据
         * @return
         */
        public static String plainEncrypt(String hexKey, String plain) {
            // 将返回的hash值转换成16进制字符串
            String cipherStr = null;
            try {
                //将字符串转换成byte数组
                byte[] srcData = plain.getBytes(CustomConstants.CHARSET_UTF8);
                //密钥
                byte[] key = Hex.decode(hexKey);
                //调用encrypt计算hash
                byte[] encrypt = encrypt(key, srcData);
                //将返回的hash值转换成16进制字符串
                cipherStr = Hex.toHexString(encrypt);
            } catch (Exception e) {
                log.error("将字符串转换为字节时出现异常:", e);
            }
            return cipherStr;
        }
    
        /**
         * SM3计算hashCode
         * @param srcData   待计算数据
         * @return
         */
        public static byte[] encrypt(byte[] srcData) {
            SM3Digest sm3Digest = new SM3Digest();
            sm3Digest.update(srcData, 0, srcData.length);
            byte[] encrypt = new byte[sm3Digest.getDigestSize()];
            sm3Digest.doFinal(encrypt, 0);
            return encrypt;
        }
    
        /**
         * 通过密钥进行加密
         * @param key       密钥byte数组
         * @param srcData   被加密的byte数组
         * @return
         */
        public static byte[] encrypt(byte[] key, byte[] srcData) {
            KeyParameter keyParameter = new KeyParameter(key);
            SM3Digest digest = new SM3Digest();
            HMac mac = new HMac(digest);
            mac.init(keyParameter);
            mac.update(srcData, 0, srcData.length);
            byte[] result = new byte[mac.getMacSize()];
            mac.doFinal(result, 0);
            return result;
        }
    
        /**
         * SM3计算hashCode
         * @param srcData   待计算数据
         * @return
         * @throws Exception
         */
        public static byte[] encrypt_0(byte[] srcData) throws Exception {
            MessageDigest messageDigest = MessageDigest.getInstance("SM3", "BC");
            byte[] digest = messageDigest.digest(srcData);
            return digest;
        }
    
    }

    SM4算法:

    import org.bouncycastle.crypto.engines.SM4Engine;
    import org.bouncycastle.crypto.params.KeyParameter;
    import org.bouncycastle.util.encoders.Hex;
    
    /**
     * @Author: dzy
     * @Date: 2018/10/9 16:41
     * @Describe: SM4算法
     */
    public class SM4Util {
    
        //加解密的字节快大小
        public static final int BLOCK_SIZE = 16;
    
        /**
         * SM4ECB加密算法
         * @param in            待加密内容
         * @param keyBytes      密钥
         * @return
         */
        public static byte[] encryptByEcb0(byte[] in, byte[] keyBytes) {
            SM4Engine sm4Engine = new SM4Engine();
            sm4Engine.init(true, new KeyParameter(keyBytes));
            int inLen = in.length;
            byte[] out = new byte[inLen];
    
            int times = inLen / BLOCK_SIZE;
    
            for (int i = 0; i < times; i++) {
                sm4Engine.processBlock(in, i * BLOCK_SIZE, out, i * BLOCK_SIZE);
            }
    
            return out;
        }
    
        /**
         * SM4ECB加密算法
         * @param in            待加密内容
         * @param keyBytes      密钥
         * @return
         */
        public static String encryptByEcb(byte[] in, byte[] keyBytes) {
            byte[] out = encryptByEcb0(in, keyBytes);
            String cipher = Hex.toHexString(out);
            return cipher;
        }
    
        /**
         * SM4的ECB加密算法
         * @param content   待加密内容
         * @param key       密钥
         * @return
         */
        public static String encryptByEcb(String content, String key) {
            byte[] in = Hex.decode(content);
            byte[] keyBytes = Hex.decode(key);
    
            String cipher = encryptByEcb(in, keyBytes);
            return cipher;
        }
    
        /**
         * SM4的ECB解密算法
         * @param in        密文内容
         * @param keyBytes  密钥
         * @return
         */
        public static byte[] decryptByEcb0(byte[] in, byte[] keyBytes) {
            SM4Engine sm4Engine = new SM4Engine();
            sm4Engine.init(false, new KeyParameter(keyBytes));
            int inLen = in.length;
            byte[] out = new byte[inLen];
    
            int times = inLen / BLOCK_SIZE;
    
            for (int i = 0; i < times; i++) {
                sm4Engine.processBlock(in, i * BLOCK_SIZE, out, i * BLOCK_SIZE);
            }
    
            return out;
        }
    
        /**
         * SM4的ECB解密算法
         * @param in        密文内容
         * @param keyBytes  密钥
         * @return
         */
        public static String decryptByEcb(byte[] in, byte[] keyBytes) {
            byte[] out = decryptByEcb0(in, keyBytes);
            String plain = Hex.toHexString(out);
            return plain;
        }
    
        /**
         * SM4的ECB解密算法
         * @param cipher    密文内容
         * @param key       密钥
         * @return
         */
        public static String decryptByEcb(String cipher, String key) {
            byte[] in = Hex.decode(cipher);
            byte[] keyBytes = Hex.decode(key);
    
            String plain = decryptByEcb(in, keyBytes);
            return plain;
        }
    
    }
  • 相关阅读:
    思考的容器:结构
    思维的结构-结构是思维的组织形式-系统思维
    分层 抽象 复杂 认知
    NoSQL 简介
    什么是数据库ACID?
    sqlite3 多线程和锁 ,优化插入速度及性能优化
    Architecture of SQLite
    关系模型我的理解
    科学理论--抽象
    认识的三个层次
  • 原文地址:https://www.cnblogs.com/alsodzy/p/9854521.html
Copyright © 2011-2022 走看看