当前位置:   article > 正文

JAVA集成国密SM2_java sm2

java sm2

国密算法概述:https://blog.csdn.net/qq_38254635/article/details/131801527

SM2椭圆曲线公钥密码算法
非对称加密,基于ECC。该算法已公开。由于该算法基于ECC,故其签名速度与秘钥生成速度都快于RSA。ECC 256位(SM2采用的就是ECC 256位的一种)安全强度比RSA 2048位高,但运算速度快于RSA。

一、pom配置

<!-- 国密 -->
<dependency>
	<groupId>org.bouncycastle</groupId>
	<artifactId>bcprov-jdk15to18</artifactId>
	<version>1.66</version>
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

二、代码集成

2.1、目录结构

在这里插入图片描述

2.2、源码

KeyConstant.java

package com.secret.sm2;

public class KeyConstant {

    public static final String PRIVATE_KEY = "pveky"; // 私钥
    public static final String PUBLIC_KEY = "pbcky"; // 公钥

    public static final String GM_NAME_CURVE = "sm2p256v1";
    public static final String ALGORITHM = "SHA1PRNG";

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

ModeTypeConstant.java

package com.secret.sm2;

import org.bouncycastle.crypto.engines.SM2Engine;

public class ModeTypeConstant {

    public static final String BASE = "base";
    public static final String BC = "bc";

    @Deprecated
    public static final SM2Engine.Mode BASE_MODE = SM2Engine.Mode.C1C3C2;
    @Deprecated
    public static final SM2Engine.Mode BC_MODE = SM2Engine.Mode.C1C2C3;

    public static ModeTypeEnum getMode(String modeType){
        if (ModeTypeEnum.BASE_MODE.getType().equals(modeType)) return ModeTypeEnum.BASE_MODE;
        return ModeTypeEnum.BC_MODE;
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

ModeTypeEnum.java

package com.secret.sm2;

import org.bouncycastle.crypto.engines.SM2Engine;

public enum ModeTypeEnum {

    BASE_MODE(ModeTypeConstant.BASE, SM2Engine.Mode.C1C3C2),
    BC_MODE(ModeTypeConstant.BC, SM2Engine.Mode.C1C2C3);

    private String type;
    private SM2Engine.Mode mode;

    ModeTypeEnum(String type, SM2Engine.Mode mode) {
        this.type = type;
        this.mode = mode;
    }

    public String getType(){
        return type;
    }

    public SM2Engine.Mode getMode(){
        return mode;
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

SecretCommon.java

package com.secret.sm2;

import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
import org.bouncycastle.util.encoders.Hex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.HashMap;
import java.util.Map;

/**
 * SM2公钥密码算法(非对称算法)
 * SM2椭圆曲线公钥密码算法是我国自主设计的公钥密码算法。
 * 包括SM2-1椭圆曲线数字签名算法;SM2-2椭圆曲线密钥交换协议;SM2-3椭圆曲线公钥加密算法,分别用于实现数字签名密钥协商和数据加密等功能。
 * SM2算法与RSA算法不同的是,SM2算法是基于椭圆曲线上点群离散对数难题,相对于RSA算法,256位的SM2密码强度已经比2048位的RSA密码强度要高。
 */
public class SecretCommon {

    //获取椭圆曲线
    public static synchronized ECDomainParameters getECDomainParameters() {
        X9ECParameters sm2ECParameters = GMNamedCurves.getByName(KeyConstant.GM_NAME_CURVE);
        return new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN());
    }

    /**
     * get key pair
     */
    public static Map<String, String> createKeyPair() throws NoSuchAlgorithmException {
        ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator();
        keyPairGenerator.init(new ECKeyGenerationParameters(getECDomainParameters(), SecureRandom.getInstance(KeyConstant.ALGORITHM)));
        AsymmetricCipherKeyPair asymmetricCipherKeyPair = keyPairGenerator.generateKeyPair();
        Map<String, String> map = new HashMap<>();
        BigInteger bigInteger = ((ECPrivateKeyParameters) asymmetricCipherKeyPair.getPrivate()).getD();
        map.put(KeyConstant.PRIVATE_KEY, ByteUtils.toHexString(bigInteger.toByteArray()));
        // 把公钥放入map中,默认压缩公钥
        // 公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥,04的时候,可以去掉前面的04
        ECPoint ecPoint = ((ECPublicKeyParameters) asymmetricCipherKeyPair.getPublic()).getQ();
        map.put(KeyConstant.PUBLIC_KEY, ByteUtils.toHexString(ecPoint.getEncoded(false)));
        return map;
    }

    /**
     * 加密
     * @param plainText 需加密的明文字符串
     * @param publicKey 公钥
     * @param modeType base:标准;bc:BC模式
     */
    public static String encrypt(String plainText, String publicKey, ModeTypeEnum modeType) throws IOException, InvalidCipherTextException {
        return encrypt(plainText.getBytes(), publicKey, modeType.getMode());
    }

    /**
     * 加密
     * @param plainByte 需加密的明文字节数组
     * @param publicKey 公钥
     * @param mode 加密模式 ModeTypeEnum
     */
    public static String encrypt(byte[] plainByte, String publicKey, SM2Engine.Mode mode) throws IOException, InvalidCipherTextException {
        ECDomainParameters domainParameters = getECDomainParameters();
        //提取公钥点
        ECPoint ecPoint = domainParameters.getCurve().decodePoint(ByteUtils.fromHexString(publicKey));
        // 公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥, 04的时候,可以去掉前面的04
        ECPublicKeyParameters publicKeyParameters = new ECPublicKeyParameters(ecPoint, domainParameters);
        SM2Engine sm2Engine = new SM2Engine(mode);
        sm2Engine.init(true, new ParametersWithRandom(publicKeyParameters, new SecureRandom()));
        return ByteUtils.toHexString(sm2Engine.processBlock(plainByte, 0, plainByte.length));
    }

    /**
     * 解密
     * @param cipherText 需加密的字符串
     * @param privateKey 私钥
     * @param modeType base:标准;bc:BC模式
     */
    public static String decrypt(String cipherText, String privateKey, ModeTypeEnum modeType) throws InvalidCipherTextException, UnsupportedEncodingException {
        return decrypt(Hex.decode(cipherText), privateKey, modeType.getMode());
    }

    /**
     * 解密
     * @param cipherDataByte 密文字节数组
     * @param privateKeyHex 私钥
     * @param mode 解密模式 ModeTypeEnum
     */
    public static String decrypt(byte[] cipherDataByte, String privateKeyHex, SM2Engine.Mode mode) throws InvalidCipherTextException, UnsupportedEncodingException {
        BigInteger bigInteger = new BigInteger(privateKeyHex, 16);
        ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(bigInteger, getECDomainParameters());
        SM2Engine sm2Engine = new SM2Engine(mode);
        sm2Engine.init(false, privateKeyParameters);
        return new String(sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length), "utf-8");
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109

Utils.java

package com.secret.sm2;

import org.bouncycastle.crypto.InvalidCipherTextException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.util.Map;

public class Utils {

    /**
     * get key pair
     */
    public static Map<String, String> createKeyPair() throws NoSuchAlgorithmException {
        return SecretCommon.createKeyPair();
    }

    /**
     * encrypt
     * @param plainText 需加密的明文字符串
     * @param publicKey 公钥
     */
    public static String encrypt(String plainText, String publicKey) throws IOException, InvalidCipherTextException {
        return encrypt(plainText, publicKey, ModeTypeConstant.BASE);
    }

    /**
     * encrypt
     * @param plainText 需加密的明文字符串
     * @param publicKey 公钥
     * @param modeType base:标准;bc:BC模式
     */
    public static String encrypt(String plainText, String publicKey, String modeType) throws IOException, InvalidCipherTextException {
        return SecretCommon.encrypt(plainText, publicKey, ModeTypeConstant.getMode(modeType));
    }

    /**
     * decrypt
     * @param cipherText 需加密的字符串
     * @param privateKey 私钥
     */
    public static String decrypt(String cipherText, String privateKey) throws InvalidCipherTextException, UnsupportedEncodingException {
        return decrypt(cipherText, privateKey, ModeTypeConstant.BASE);
    }

    /**
     * decrypt
     * @param cipherText 需加密的字符串
     * @param privateKey 私钥
     * @param modeType base:标准;bc:BC模式
     */
    public static String decrypt(String cipherText, String privateKey, String modeType) throws InvalidCipherTextException, UnsupportedEncodingException {
        return SecretCommon.decrypt(cipherText, privateKey, ModeTypeConstant.getMode(modeType));
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56

测试类:Test.java

package com.secret.sm2;

import java.util.Map;

public class Test {

    public static void main(String[] args) throws Exception {
        Map<String, String> createKeyPair = Utils.createKeyPair();
        System.out.println("秘钥对:" + createKeyPair);
        String privateKey = createKeyPair.get(KeyConstant.PRIVATE_KEY);
        String publicKey = createKeyPair.get(KeyConstant.PUBLIC_KEY);
        String text = "I believe you can do anything";
        String encrypt = Utils.encrypt(text, publicKey);
        System.out.println("加密后密文:" + encrypt);
        String decrypt = Utils.decrypt(encrypt, privateKey);
        System.out.println("解密后明文:" + decrypt);
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

2.3、测试

测试结果如图:
在这里插入图片描述
使用方法参考测试类即可。

三、相关链接

国密算法概述:https://blog.csdn.net/qq_38254635/article/details/131801527

JAVA集成国密SM3:https://blog.csdn.net/qq_38254635/article/details/131810696

JAVA集成国密SM4:https://blog.csdn.net/qq_38254635/article/details/131810715

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/589358
推荐阅读
相关标签
  

闽ICP备14008679号