国密即国家密码局认定的国产密码算法。主要有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
* @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 公钥
* @param data 需要加密的数据
* @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 私钥
* @param encryptedData 需要解密的内容
* @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);
}
}