Java实现SM2算法(国密算法)

18 篇文章 2 订阅
2 篇文章 0 订阅

Java实现SM2算法(国密算法)

国密即国家密码局认定的国产密码算法。主要有SM1,SM2,SM3,SM4。密钥长度和分组长度均为128位
一、SM1 为对称加密。其加密强度与AES相当。该算法不公开,调用该算法时,需要通过加密芯片的接口进行调用。
二、SM2为非对称加密,基于ECC。该算法已公开。由于该算法基于ECC,故其签名速度与秘钥生成速度都快于RSA。ECC 256位(SM2采用的就是ECC 256位的一种)安全强度比RSA 2048位高,但运算速度快于RSA。
三、SM3 消息摘要。可以用MD5作为对比理解。该算法已公开。校验结果为256位。
四、SM4 无线局域网标准的分组数据算法。对称加密,密钥长度和分组长度均为128位。

POM依赖:

<!--国密-->
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.56</version>
</dependency>

SM2加解密代码:

/**
 * @author SongWei
 * @version 1.0.0
 * @ClassName spring-cloud.com.boot.cloud.encryption.sm.Sm2Utils.java
 * @Description SM2加解密工具类
 * @createTime 2018年10月28日 13:57:00
 */
public class Sm2Utils{
    /**
     * 生成随机秘钥对
     *
     * @Version: 1.0.0
     * @return: Map<String, String>
     * @author: SongWei
     * @date: 2018/10/28 13:57
     */
    public static Map<String, String> generateKeyPair() {
        SM2 sm2 = SM2.Instance();
        AsymmetricCipherKeyPair key = sm2.ecc_key_pair_generator.generateKeyPair();
        ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters) key.getPrivate();
        ECPublicKeyParameters ecpub = (ECPublicKeyParameters) key.getPublic();
        //解密密钥
        BigInteger privateKey = ecpriv.getD(); 
        //加密密钥
        ECPoint publicKey = ecpub.getQ();  
        Map<String, String> resutlMap = new HashMap<String, String>();
        resutlMap.put("privateKey", SecurityUtils.byteToHex(privateKey.toByteArray()));
        resutlMap.put("publicKey", SecurityUtils.byteToHex(publicKey.getEncoded()));
        return resutlMap;
    }

    /**
     * SM2加密
     *
     * @param publicKey <p>公钥</p>
     * @param data      <p>需要加密的数据</p>
     * @Version: 1.0.0
     * @return: String
     * @author: SongWei
     * @date: 2018/10/28 13:57
     */
    public static String encrypt(byte[] publicKey, byte[] data) throws IOException {
        if (publicKey == null || publicKey.length == 0) {
            return null;
        }
        if (data == null || data.length == 0) {
            return null;
        }
        byte[] source = new byte[data.length];
        System.arraycopy(data, 0, source, 0, data.length);
        Cipher cipher = new Cipher();
        SM2 sm2 = SM2.Instance();
        ECPoint userKey = sm2.ecc_curve.decodePoint(publicKey);
        ECPoint c1 = cipher.Init_enc(sm2, userKey);
        cipher.Encrypt(source);
        byte[] c3 = new byte[32];
        cipher.Dofinal(c3);
        //C1 C2 C3拼装成加密字串
        return SecurityUtils.byteToHex(c1.getEncoded()) + SecurityUtils.byteToHex(source) + SecurityUtils.byteToHex(c3);

    }

    /**
     * 数据解密
     *
     * @param privateKey    <p>私钥</p>
     * @param encryptedData <p>需要解密的内容</p>
     * @Version: 1.0.0
     * @return: byte
     * @author: SongWei
     * @date: 2018/10/18 13:59
     */
    public static byte[] decrypt(byte[] privateKey, byte[] encryptedData) throws IOException {
        if (privateKey == null || privateKey.length == 0) {
            return null;
        }
        if (encryptedData == null || encryptedData.length == 0) {
            return null;
        }
        //加密字节数组转换为十六进制的字符串 长度变为encryptedData.length * 2
        String data = SecurityUtils.byteToHex(encryptedData);
        /**
         *	分解加密字串
         * (C1 = C1标志位2位 + C1实体部分128位 = 130)
         * (C3 = C3实体部分64位  = 64)
         * (C2 = encryptedData.length * 2 - C1长度  - C2长度)
         */
        byte[] c1Bytes = SecurityUtils.hexToByte(data.substring(0, 130));
        int c2Len = encryptedData.length - 97;
        byte[] c2 = SecurityUtils.hexToByte(data.substring(130, 130 + 2 * c2Len));
        byte[] c3 = SecurityUtils.hexToByte(data.substring(130 + 2 * c2Len, 194 + 2 * c2Len));
        SM2 sm2 = SM2.Instance();
        BigInteger userD = new BigInteger(1, privateKey);
        //通过C1实体字节来生成ECPoint
        ECPoint c1 = sm2.ecc_curve.decodePoint(c1Bytes);
        Cipher cipher = new Cipher();
        cipher.Init_dec(userD, c1);
        cipher.Decrypt(c2);
        cipher.Dofinal(c3);
        //返回解密结果
        return c2;
    }

    public static void main(String[] args) throws Exception {
        for (int i = 0; i < 200; i++) {
            //生成密钥对
            Map<String, String> keyMap = generateKeyPair();
            String plainText = "{"id":"123","name":"张三"}";
            加密密钥
            String publicKey = keyMap.get("publicKey");
            //解密蜜月
            String privateKey = keyMap.get("privateKey");
            String encString = SM2Utils.encrypt(SecurityUtils.hexStringToBytes(publicKey), plainText.getBytes());
            System.out.println("密文:" + encString);
            byte[] plainString = SM2Utils.decrypt(SecurityUtils.hexStringToBytes(privateKey), SecurityUtils.hexStringToBytes(encString));
            System.out.println(new String(plainString));
        }
    }
}
/**
 * @author SongWei
 * @version 1.0.0
 * @ClassName spring-cloud.com.boot.cloud.sm.Sm2Tool.java
 * @Description TODO
 * @createTime 2018年10月28日 14:29:00
 */
public class Sm2Tool {

    /**
     * 正式参数
     *
     * @Version: 1.0.0
     * @date: 2018年10月28日 14:29:00
     */
    public static String[] ecc_param = {
            "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF",
            "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC",
            "28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93",
            "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123",
            "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7",
            "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0"
    };

    public static Sm2Tool Instance() {
        return new Sm2Tool();
    }

    public final BigInteger ecc_p;
    public final BigInteger ecc_a;
    public final BigInteger ecc_b;
    public final BigInteger ecc_n;
    public final BigInteger ecc_gx;
    public final BigInteger ecc_gy;
    public final ECCurve ecc_curve;
    public final ECPoint ecc_point_g;
    public final ECDomainParameters ecc_bc_spec;
    public final ECKeyPairGenerator ecc_key_pair_generator;
    public final ECFieldElement ecc_gx_fieldsmen;
    public final ECFieldElement ecc_gy_fieldsmen;


    public Sm2Tool() {
        this.ecc_p = new BigInteger(ecc_param[0], 16);
        this.ecc_a = new BigInteger(ecc_param[1], 16);
        this.ecc_b = new BigInteger(ecc_param[2], 16);
        this.ecc_n = new BigInteger(ecc_param[3], 16);
        this.ecc_gx = new BigInteger(ecc_param[4], 16);
        this.ecc_gy = new BigInteger(ecc_param[5], 16);
        this.ecc_gx_fieldsmen = new Fp(this.ecc_p, this.ecc_gx);
        this.ecc_gy_fieldsmen = new Fp(this.ecc_p, this.ecc_gy);
        this.ecc_curve = new ECCurve.Fp(this.ecc_p, this.ecc_a, this.ecc_b);
        this.ecc_point_g = new ECPoint.Fp(this.ecc_curve, this.ecc_gx_fieldsmen, this.ecc_gy_fieldsmen);
        this.ecc_bc_spec = new ECDomainParameters(this.ecc_curve, this.ecc_point_g, this.ecc_n);
        ECKeyGenerationParameters ecc_engender;
        ecc_engender = new ECKeyGenerationParameters(this.ecc_bc_spec, new SecureRandom());
        this.ecc_key_pair_generator = new ECKeyPairGenerator();
        this.ecc_key_pair_generator.init(ecc_engender);
    }
}

此文章是SM2加解密代码,后续更新SM3和其他工具类(后续更新完整SM2代码)

  • 17
    点赞
  • 110
    收藏
    觉得还不错? 一键收藏
  • 24
    评论
好的,关于Java基于SM2国密算法传输数据,需要先引入Bouncy Castle库,它是一个提供了许多加密算法支持的开源库。接下来,我们需要使用SM2算法进行加密和解密。 下面是使用SM2算法进行加密和解密的基本步骤: 1. 生成SM2密钥对,包括公钥和私钥。 2. 使用公钥进行加密,将明文数据进行加密,得到密文。 3. 使用私钥进行解密,将密文进行解密,得到明文数据。 下面是一个简单的Java代码示例,演示了如何使用SM2算法进行加密和解密: ``` import org.bouncycastle.crypto.AsymmetricCipherKeyPair; import org.bouncycastle.crypto.generators.ECKeyPairGenerator; import org.bouncycastle.crypto.params.ECPrivateKeyParameters; import org.bouncycastle.crypto.params.ECPublicKeyParameters; import org.bouncycastle.crypto.params.ParametersWithRandom; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.util.encoders.Hex; import java.security.Security; public class SM2EncryptionDemo { public static void main(String[] args) throws Exception { Security.addProvider(new BouncyCastleProvider()); // 生成SM2密钥对 ECKeyPairGenerator generator = new ECKeyPairGenerator(); generator.init(new ParametersWithRandom(SM2Util.getSM2ParameterSpec(), new SecureRandom())); AsymmetricCipherKeyPair keyPair = generator.generateKeyPair(); ECPrivateKeyParameters privateKey = (ECPrivateKeyParameters) keyPair.getPrivate(); ECPublicKeyParameters publicKey = (ECPublicKeyParameters) keyPair.getPublic(); // 明文数据 String plainText = "Hello, world!"; // 使用公钥进行加密 byte[] cipherText = SM2Util.encrypt(publicKey, plainText.getBytes()); // 使用私钥进行解密 byte[] decryptedData = SM2Util.decrypt(privateKey, cipherText); String decryptedText = new String(decryptedData); System.out.println("明文数据: " + plainText); System.out.println("加密后的数据:" + Hex.toHexString(cipherText)); System.out.println("解密后的数据:" + decryptedText); } } ``` 需要注意的是,SM2算法需要使用国密规范的参数,可以使用Bouncy Castle库中提供的SM2Util类来获取SM2相关参数。具体实现细节可以参考相关文档和API。
评论 24
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值