首先来看一下什么是国密算法:
国密即国家密码局认定的国产密码算法,即商用密码。
国密主要有SM1,SM2,SM3,SM4。密钥长度和分组长度均为128位。
1、SM1 为对称加密。其加密强度与AES(高级加密标准,Advanced Encryption Standard)相当。该算法不公开,调用该算法时,需要通过加密芯片的接口进行调用。
2、SM2为非对称加密,基于ECC。该算法已公开。由于该算法基于ECC,故其签名速度与秘钥生成速度都快于RSA。ECC 256位(SM2采用的就是ECC 256位的一种)安全强度比RSA 2048位高,但运算速度快于RSA。
3、SM3为消息摘要。可以用MD5作为对比理解。该算法已公开。校验结果为256位。
4、SM4为无线局域网标准的分组数据算法。对称加密,密钥长度和分组长度均为128位。
由于SM1、SM4加解密的分组大小为128bit,故对消息进行加解密时,若消息长度过长,需要进行分组,要消息长度不足,则要进行填充。
在很多地方还是会用到的,这里说一下这个:SM2
1.在pom.xml中引入依赖jar包:
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.58</version>
</dependency>
2.然后来写一个工具类,用来生成国密的,公钥和私钥 这个密码对.
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.security.*;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
/**
* @author hulala
* @Description 国密公私钥对 工具类
*/
public class KeyUtils {
/**
* 生成国密公私钥对
*
* @return
* @throws Exception
*/
public static String[] generateSmKey() throws Exception {
KeyPairGenerator keyPairGenerator = null;
SecureRandom secureRandom = new SecureRandom();
ECGenParameterSpec sm2Spec = new ECGenParameterSpec("sm2p256v1");
keyPairGenerator = KeyPairGenerator.getInstance("EC", new BouncyCastleProvider());
keyPairGenerator.initialize(sm2Spec);
keyPairGenerator.initialize(sm2Spec, secureRandom);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();
//String[0] 公钥
//String[1] 私钥
String[] result = {
new String(Base64.getEncoder().encode(publicKey.getEncoded()))
, new String(Base64.getEncoder().encode(privateKey.getEncoded()))
};
return result;
}
/**
* 将Base64转码的公钥串,转化为公钥对象
*
* @param publicKey
* @return
*/
public static PublicKey createPublicKey(String publicKey) {
PublicKey publickey = null;
try {
X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(publicKey));
KeyFactory keyFactory = KeyFactory.getInstance("EC", new BouncyCastleProvider());
publickey = keyFactory.generatePublic(publicKeySpec);
} catch (Exception e) {
e.printStackTrace();
}
return publickey;
}
/**
* 将Base64转码的私钥串,转化为私钥对象
*
* @param privateKey
* @return
*/
public static PrivateKey createPrivateKey(String privateKey) {
PrivateKey publickey = null;
try {
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey));
KeyFactory keyFactory = KeyFactory.getInstance("EC", new BouncyCastleProvider());
publickey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
} catch (Exception e) {
e.printStackTrace();
}
return publickey;
}
}
3.根据公钥和私钥工具类,生成的密钥对,对数据,进行加密和解密操作
import org.bouncycastle.asn1.gm.GMObjectIdentifiers;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECParameterSpec;
import java.security.*;
/**
* @author hulala
* @Description SM2实现工具类
*/
public class Sm2Util {
static {
Security.addProvider(new BouncyCastleProvider());
}
/**
* 根据publicKey对原始数据data,使用SM2加密
*
* @param data
* @param publicKey
* @return
*/
public static byte[] encrypt(byte[] data, PublicKey publicKey) {
ECPublicKeyParameters localECPublicKeyParameters = null;
if (publicKey instanceof BCECPublicKey) {
BCECPublicKey localECPublicKey = (BCECPublicKey) publicKey;
ECParameterSpec localECParameterSpec = localECPublicKey.getParameters();
ECDomainParameters localECDomainParameters = new ECDomainParameters(localECParameterSpec.getCurve(),
localECParameterSpec.getG(), localECParameterSpec.getN());
localECPublicKeyParameters = new ECPublicKeyParameters(localECPublicKey.getQ(), localECDomainParameters);
}
SM2Engine localSM2Engine = new SM2Engine();
localSM2Engine.init(true, new ParametersWithRandom(localECPublicKeyParameters, new SecureRandom()));
byte[] arrayOfByte2;
try {
arrayOfByte2 = localSM2Engine.processBlock(data, 0, data.length);
return arrayOfByte2;
} catch (InvalidCipherTextException e) {
e.printStackTrace();
return null;
}
}
/**
* 根据privateKey对加密数据encodedata,使用SM2解密
*
* @param encodedata
* @param privateKey
* @return
*/
public static byte[] decrypt(byte[] encodedata, PrivateKey privateKey) {
SM2Engine localSM2Engine = new SM2Engine();
BCECPrivateKey sm2PriK = (BCECPrivateKey) privateKey;
ECParameterSpec localECParameterSpec = sm2PriK.getParameters();
ECDomainParameters localECDomainParameters = new ECDomainParameters(localECParameterSpec.getCurve(),
localECParameterSpec.getG(), localECParameterSpec.getN());
ECPrivateKeyParameters localECPrivateKeyParameters = new ECPrivateKeyParameters(sm2PriK.getD(),
localECDomainParameters);
localSM2Engine.init(false, localECPrivateKeyParameters);
try {
byte[] arrayOfByte3 = localSM2Engine.processBlock(encodedata, 0, encodedata.length);
return arrayOfByte3;
} catch (InvalidCipherTextException e) {
e.printStackTrace();
return null;
}
}
/**
* 私钥签名
*
* @param data
* @param privateKey
* @return
* @throws Exception
*/
public static byte[] signByPrivateKey(byte[] data, PrivateKey privateKey) throws Exception {
Signature sig = Signature.getInstance(GMObjectIdentifiers.sm2sign_with_sm3.toString(), BouncyCastleProvider.PROVIDER_NAME);
sig.initSign(privateKey);
sig.update(data);
byte[] ret = sig.sign();
return ret;
}
/**
* 公钥验签
*
* @param data
* @param publicKey
* @para