JAVA集成国密SM2加解密
国密算法概述:https://blog.csdn.net/qq_38254635/article/details/131801527
SM2椭圆曲线公钥密码算法
为非对称加密,基于ECC。该算法已公开。由于该算法基于ECC,故其签名速度与秘钥生成速度都快于RSA。ECC 256位(SM2采用的就是ECC 256位的一种)安全强度比RSA 2048位高,但运算速度快于RSA。
一、pom配置
java
<!-- 国密 -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15to18</artifactId>
<version>1.66</version>
</dependency>
二、代码集成
2.1、目录结构
2.2、源码
KeyConstant.java
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";
}
ModeTypeConstant.java
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;
}
}
ModeTypeEnum.java
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;
}
}
SecretCommon.java
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");
}
}
Utils.java
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));
}
}
测试类:Test.java
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);
}
}
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