王子
国密算法
09/07
本文最后更新于2022年09月07日,已超过837天没有更新。如果文章内容或图片资源失效,请留言反馈,我会及时处理,谢谢!
国密即国家密码局认定的国产密码算法。主要有SM1,SM2,SM3,SM4。密钥长度和分组长度均为128位。 SM1
为对称加密。其加密强度与AES相当。该算法不公开,调用该算法时,需要通过加密芯片的接口进行调用。
SM2为非对称加密,基于ECC。该算法已公开。由于该算法基于ECC,故其签名速度与秘钥生成速度都快于RSA。ECC
256位(SM2采用的就是ECC 256位的一种)安全强度比RSA 2048位高,但运算速度快于RSA。
国家密码管理局公布的公钥算法,其加密强度为256位 SM3 消息摘要。可以用MD5作为对比理解。该算法已公开。校验结果为256位。 SM4
无线局域网标准的分组数据算法。对称加密,密钥长度和分组长度均为128位。由于SM1、SM4加解密的分组大小为128bit,故对消息进行加解密时,若消息长度过长,需要进行分组,要消息长度不足,则要进行填充。
国际算法与国密算法分类 分组密码算法(DES和SM4)、将明文数据按固定长度进行分组,然后在同一密钥控制下逐组进行加密,
公钥密码算法(RSA和SM2)、公开加密算法本身和公开公钥,保存私钥摘要算法(SM3 md5) 这个都比较熟悉,用于数字签名,消息认证,数据完整性,但是sm3安全度比md5高
总得来说国密算法的安全度比较高,2010年12月推出,也是国家安全战略,现在银行都要要求国际算法改造,要把国际算法都给去掉。
1.Java实现SM3加密和验证
在商用密码体系中,SM3主要用于数字签名及验证、消息认证码生成及验证、随机数生成等,其算法公开。据国家密码管理局表示,其安全性及效率与SHA-256相当。
1.1需要引入如下坐标依赖:
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.68</version>
</dependency>
1.2自定义密钥加密及校验
1.2.1加密
private static final String ENCODING = "UTF-8";
/**
* 加密
*
* @param src 明文
* @param key 密钥
* @return
* @throws Exception
*/
public static String encrypt(String src, String key) throws Exception {
return ByteUtils.toHexString(getEncryptByKey(src, key));
}
/**
* SM3加密方式之: 根据自定义密钥进行加密,返回加密后长度为32位的16进制字符串
*
* @param src 源数据
* @param key 密钥
* @return
* @throws Exception
*/
public static byte[] getEncryptByKey(String src, String key) throws Exception {
byte[] srcByte = src.getBytes(ENCODING);
byte[] keyByte = key.getBytes(ENCODING);
KeyParameter keyParameter = new KeyParameter(keyByte);
SM3Digest sm3 = new SM3Digest();
HMac hMac = new HMac(sm3);
hMac.init(keyParameter);
hMac.update(srcByte, 0, srcByte.length);
byte[] result = new byte[hMac.getMacSize()];
hMac.doFinal(result, 0);
return result;
}
1.2.2 校验
/**
* 利用源数据+密钥校验与密文是否一致
*
* @param src 源数据
* @param key 密钥
* @param sm3HexStr 密文
* @return
* @throws Exception
*/
public static boolean verify(String src, String key, String sm3HexStr) throws Exception {
byte[] sm3HashCode = ByteUtils.fromHexString(sm3HexStr);
byte[] newHashCode = getEncryptByKey(src, key);
return Arrays.equals(newHashCode, sm3HashCode);
}
1.3无密钥的加密及校验
1.3.1加密
/**
* SM3加密方式之:不提供密钥的方式 SM3加密,返回加密后长度为64位的16进制字符串
*
* @param src 明文
* @return
*/
public static String encrypt(String src) {
return ByteUtils.toHexString(getEncryptBySrcByte(src.getBytes()));
}
/**
* 返回长度为32位的加密后的byte数组
*
* @param srcByte
* @return
*/
public static byte[] getEncryptBySrcByte(byte[] srcByte) {
SM3Digest sm3 = new SM3Digest();
sm3.update(srcByte, 0, srcByte.length);
byte[] encryptByte = new byte[sm3.getDigestSize()];
sm3.doFinal(encryptByte, 0);
return encryptByte;
}
1.3.2校验
/**
* 校验源数据与加密数据是否一致
*
* @param src 源数据
* @param sm3HexStr 16进制的加密数据
* @return
* @throws Exception
*/
public static boolean verify(String src, String sm3HexStr) throws Exception {
byte[] sm3HashCode = ByteUtils.fromHexString(sm3HexStr);
byte[] newHashCode = getEncryptBySrcByte(src.getBytes(ENCODING));
return Arrays.equals(newHashCode, sm3HashCode);
}
1.4测试验证
public static void main(String[] args) throws Exception {
String srcStr = "今天天气很晴朗";
String key = "zjqzjq";
// ******************************自定义密钥加密及校验*****************************************
String hexStrByKey = SM3Utils.encrypt(srcStr, key);
System.out.println("带密钥加密后的密文:" + hexStrByKey);
System.out.println("明文(带密钥)与密文校验结果:" + SM3Utils.verify(srcStr, key, hexStrByKey));
// ******************************无密钥的加密及校验******************************************
String hexStrNoKey = SM3Utils.encrypt(srcStr);
System.out.println("不带密钥加密后的密文:" + hexStrNoKey);
System.out.println("明文(不带密钥)与密文校验结果:" + SM3Utils.verify(srcStr, hexStrNoKey));
}
结果输出如下:
2.前端使用sm2、sm3加密解密 案例
2.1 安装:
npm install --save sm-crypto
2.2 引入:
const sm2 = require('sm-crypto').sm2
const cipherMode = 1 // 1 - C1C3C2,0 - C1C2C3,默认为1
2.3 加密:
let encryptData = sm2.doEncrypt(msgString, publicKey, cipherMode) // 加密结果
conso.log("加密结果:",encryptData);
2.4 解密:
let decryptData sm2.doDecrypt(encryptData, privateKey, cipherMode) // 解密结果
conso.log("解密结果:",encryptData);