国密算法是指中国自主设计和使用的密码算法标准,其目的是保障信息安全和国家利益。
国密算法包括以下几个主要的密码算法:
算法名称 | 类别 | 应用领域 | 特點 |
---|---|---|---|
SM1 | 分组加密算法 | 芯片 | 不公開 |
SM2 | 椭圆曲线公钥加密算法 | 數據加密 | 基于ECC算法的非对称密钥算法,其加密强度为256位 |
SM3 | 散列函数算法 | 完整性校驗,哈希(摘要)算法 | 不可逆的算法,功能与MD5,SHA-1相同 |
SM4 | 對稱加密算法 | 數據加密和局域網 | 分组长度为128比特,密钥长度为128比特 |
SM7 | 對稱加密算法 | 非接觸式IC卡 | 组长度为128比特,密钥长度为128比特 |
SM9 | 標識加密算法 | 端對端離線安全通信 | 加密强度等同于3072位密钥的RSA加密算法 |
ZUC | 對稱加密算法,祖冲之算法 | 移動通信 | 流密碼 |
1、SM1 分组加密算法
SM1 为分组加密算法,对称加密,分组长度和密钥长度都为 128 位,故对消息进行加解密时,若消息长度过长,需要进行分组,要消息长度不足,则要进行填充。算法安全保密强度及相关软硬件实现性能与 AES 相当,该算法不公开,仅以 IP 核的形式存在于芯片中,调用该算法时,需要通过加密芯片的接口进行调用,采用该算法已经研制了系列芯片、智能 IC 卡、智能密码钥匙、加密卡、加密机等安全产品,广泛应用于电子政务、电子商务及国民经济的各个应用领域(包括国家政务通、警务通等重要领域)。
2、SM2 椭圆曲线公钥加密算法
SM2是国家密码管理局于2010年12月17日发布的椭圆曲线公钥密码算法。
该算法是一种基于ECC算法的非对称密钥算法,其加密强度为256位,其安全性与目前使用的RSA1024相比具有明显的优势。
SM2算法和RSA算法都是公钥密码算法,SM2算法是一种更先进安全的算法,在我们国家商用密码体系中被用来替换RSA算法。
随着密码技术和计算机技术的发展,目前常用的1024位RSA算法面临严重的安全威胁,我们国家密码管理部门经过研究,决定采用SM2椭圆曲线算法替换RSA算法。
SM2算法和RSA算法比较
SM2性能更优更安全:密码复杂度高、处理速度快、机器性能消耗更小。
SM2 | RSA | |
---|---|---|
算法结构 | 基本椭圆曲线(ECC) | 基于特殊的可逆模幂运算 |
计算复杂度 | 完全指数级 | 亚指数级 |
存储空间 | 192-256bit | 2048-4096bit |
秘钥生成速度 | 较RSA算法快百倍以上 | 慢 |
解密加密速度 | 较快 | 一般 |
3、SM3 杂凑算法
SM3是国家采用的一种密码散列函数标准,由国家密码管理局于2010年12月17日发布。相关标准为“GM/T 0004-2012 《SM3密码杂凑算法》”。
该算法也叫密码杂凑算法,属于哈希(摘要)算法的一种,杂凑值为256位,和SM2算法一起被公布。功能与MD5,SHA-1相同。产生256位的编码。该算法为不可逆的算法。具体算法也是保密。
在商用密码体系中,SM3主要用于数字签名及验证、消息认证码生成及验证、随机数生成等,其算法公开。据国家密码管理局表示,其安全性及效率与SHA-256相当。
密码散列函数
密码散列函数(英语:Cryptographic hash function),又译为密码散列函数、加密散列函数,是散列函数的一种。它被认为是一种单向函数,也就是说极其难以由散列函数输出的结果,回推输入的数据是什么。这样的单向函数被称为“现代密码学的驮马”。这种散列函数的输入数据,通常被称为消息(message),而它的输出结果,经常被称为消息摘要(message digest)或摘要(digest)。
在信息安全中,有许多重要的应用,都使用了密码散列函数来实现,例如数字签名,消息认证码。
特性:
- 对于任何一个给定的消息,它都很容易就能运算出散列数值。
- 难以由一个已知的散列数值,去推算出原始的消息。
- 在不更动散列数值的前提下,修改消息内容是不可行的。
- 对于两个不同的消息,它不能给与相同的散列数值。
4、SM4 分组加密算法
SM4.0(原名SMS4.0)是国家采用的一种分组密码标准,由国家密码管理局于2012年3月21日发布。相关标准为“GM/T 0002-2012《SM4分组密码算法》(原SMS4分组密码算法)”。
该算法为对称加密算法,随WAPI标准一起被公布,其加密强度为128位。此算法是一个分组算法,用于无线局域网产品。该算法的分组长度为128比特,密钥长度为128比特。加密算法与密钥扩展算法都采用32轮非线性迭代结构。解密算法与加密算法的结构相同,只是轮密钥的使用顺序相反,解密轮密钥是加密轮密钥的逆序。
在商用密码体系中,SM4主要用于数据加密,其算法公开,分组长度与密钥长度均为128bit,加密算法与密钥扩展算法都采用32轮非线性迭代结构,S盒为固定的8比特输入8比特输出。
SM4.0中的指令长度被提升到大于64K(即64×1024)的水平,这是SM 3.0规格(渲染指令长度允许大于512)的128倍。
相关概念
在密码学中,分组加密(英语:Block cipher),又称分块加密或块密码,是一种对称密钥算法。它将明文分成多个等长的模块(block),使用确定的算法和对称密钥对每组分别加密解密。分组加密是极其重要的加密协议组成,其中典型的如DES和AES作为美国政府核定的标准加密算法,应用领域从电子邮件加密到银行交易转帐,非常广泛。
5、SM7 分组加密算法
SM7算法,是一种分组密码算法,分组长度为128比特,密钥长度为128比特。SM7适用于非接触式IC卡,应用包括身份识别类应用(门禁卡、工作证、参赛证),票务类应用(大型赛事门票、展会门票),支付与通卡类应用(积分消费卡、校园一卡通、企业一卡通等)。
产品特点
SM7国密算法的安全特性
- 真随机数发生器
- 采用SM7国密算法加密保护数据交互的安全
- 采用SM7国密算法三重相互安全认证机制
- 具有8个相互独立的128位密码,支持一卡一密和一卡多用
- 每张卡具有4字节的唯一序列号
应用
SM7适用于非接IC卡应用包括身份识别类应用(门禁卡、工作证、参赛证),票务类应用(大型赛事门票、展会门票),支付与通卡类应用(积分消费卡、校园一卡通、企业一卡通、公交一卡通)。
6、SM9 标识加密算法
SM9是国家采用的一种标识密码标准,由国家密码管理局于2016年3月28日发布,相关标准为“GM/T 0044-2016 SM9标识密码算法”。
SM9是基于对的标识密码算法,与SM2类似,包含四个部分:总则,数字签名算法,密钥交换协议以及密钥封装机制和公钥加密算法。在这些算法中使用了椭圆曲线上的对这一个工具,不同于传统意义上的SM2算法,可以实现基于身份的密码体制,也就是公钥与用户的身份信息即标识相关,从而比传统意义上的公钥密码体制有许多优点,省去了证书管理等。
双线性对的双线性的性质是基于对的标识密码SM2中的总则部分同样适用于SM9,由于SM9总则中添加了适用于对的相关理论和实现基础。
在商用密码体系中,SM9主要用于用户的身份认证。据新华网公开报道,SM9的加密强度等同于3072位密钥的RSA加密算法。
几种算法对比
算法名称 | 是否可逆 | 是否对称 |
---|---|---|
SM2 | 可逆 | 非对称 |
SM2签名 | 不可逆 | 对称 |
SM3签名 | 不可逆 | – |
SM4 | 可逆 | 对称 |
SM9 | 可逆 | 对称 |
SM9签名 | 不可逆 | – |
算法名称 | 秘钥长度 |
---|---|
SM2 | 256位(64位16进制数) |
SM2签名 | 256位(64位16进制数) |
SM3签名 | – |
SM4 | 128位(32位16进制数) |
SM9 | 不限制 |
SM9签名 | 不限制 |
算法模式列:-表示不相关
是否补足列:-表示无此参数
长度关系列:M表示密文长度,m表示明文长度
国密算法作为推荐使用的加密算法,有它们自身与其他算法相较的优势:
SM2与RSA相比,SM2的密码强度更高,由于SM2算法是基于椭圆曲线上点群离散的对数难题,256位的SM2密码强度已经比2048位 RSA密码强度要高;
SM3与MD5和SHA-1相比,产生的杂凑值长度不同,SM3输出长度为256比特,MD5为128比特,SHA-1为160比特,作为杂凑算法,杂凑值越高,安全性越高,因此SM3算法的安全性要高于MD5算法和SHA-1算法;
SM4与3DES相比,SM4与AES具有相同的密钥长度(AES密钥长度为128位时)和分组长度,因此SM4安全性显著高于3DES。
JAVA
<!-- 引入bouncycastle加密库 -->
<!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15to18 -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15to18</artifactId>
<version>1.79</version>
</dependency>
SM2实现:
package tech.kunyuan.core.utils;
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.interfaces.ECPrivateKey;
import org.bouncycastle.jce.interfaces.ECPublicKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import javax.crypto.Cipher;
import java.io.File;
import java.io.FileInputStream;
import java.lang.reflect.Field;
import java.security.*;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
/**
* Description: 国密算法 SM2
* Author: ky
* DateTime: 2024-11-18 17:28
*/
public class Sm2Utils {
//密钥长度
private final static int KEY_SIZE = 256;
public static final String ALGORITHM_NAME = "EC";
//生成对应的签名,用来验签
private final static String SIGNATURE = "SHA256withECDSA";
//注册BouncyCastle加密包
static{
Security.addProvider(new BouncyCastleProvider());
}
/**
* 输出BouncyCastleProvider支持的算法,其中就有支持ECC加密的算法
*/
private static void printProvider(){
Provider provider = new BouncyCastleProvider();
for(Provider.Service service:provider.getServices()){
//System.out.println(service.getType()+":"+service.getAlgorithm());
}
}
/**
* 生成密钥对
* @return
* @throws Exception
*/
public static ECKeyPair generateKeyPair() throws Exception{
//BC即BouncyCastle加密包,EC为ECC算法
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM_NAME, BouncyCastleProvider.PROVIDER_NAME);
keyPairGenerator.initialize(KEY_SIZE, new SecureRandom());
KeyPair keyPair = keyPairGenerator.generateKeyPair();
ECPublicKey ecPublicKey = (ECPublicKey) keyPair.getPublic();
ECPrivateKey ecPrivateKey = (ECPrivateKey) keyPair.getPrivate();
String publicKeyString = Base64.encodeBase64String(ecPublicKey.getEncoded());
String privateKeyString = Base64.encodeBase64String(ecPrivateKey.getEncoded());
return new ECKeyPair(publicKeyString, privateKeyString);
}
/**
* 公钥加密
* @param text
* @param publicKeyText
* @return
* @throws Exception
*/
public static String encrypt(String publicKeyText, String text) throws Exception{
//org.apache.commons.codec.binary.Base64.decodeBase64(publicKey);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyText));
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_NAME, BouncyCastleProvider.PROVIDER_NAME);
ECPublicKey publicKey = (ECPublicKey)keyFactory.generatePublic(keySpec);
Cipher cipher = Cipher.getInstance("ECIES", BouncyCastleProvider.PROVIDER_NAME);
//setFieldValueByFieldName(cipher);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] result = cipher.doFinal(text.getBytes());
return Base64.encodeBase64String(result);
}
/**
* 私钥解密
* @param text
* @param privateKeyText
* @return
* @throws Exception
*/
public static String decrypt(String privateKeyText, String text) throws Exception{
//content是采用base64编码后的内容,方便用于传输,下面会解码为byte[]类型的值
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyText));
KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_NAME, BouncyCastleProvider.PROVIDER_NAME);
ECPrivateKey privateKey = (ECPrivateKey) keyFactory.generatePrivate(keySpec);
Cipher cipher = Cipher.getInstance("ECIES", BouncyCastleProvider.PROVIDER_NAME);
//setFieldValueByFieldName(cipher);
cipher.init(Cipher.DECRYPT_MODE,privateKey);
byte[] result = cipher.doFinal(Base64.decodeBase64(text));
return new String(result);
}
/**
* 使用反射解决因美国出口限制,ECC算法的密钥长度不能超过128的问题,如果需要的话,可以加
* @param object
*/
private static void setFieldValueByFieldName(Cipher object){
if(object == null){
return;
}
//获取Obj类的字节文件对像
Class cipher = object.getClass();
try{
//获取该类的成员变量CryptoPermission cryptoPerm;
Field cipherField = cipher.getDeclaredField("cryptoPerm");
cipherField.setAccessible(true);
Object cryptoPerm = cipherField.get(object);
//获取CryptoPermission类的成员变量maxKeySize
Class c = cryptoPerm.getClass();
Field[] cs = c.getDeclaredFields();
Field cryptoPermField = c.getDeclaredField("maxKeySize");
cryptoPermField.setAccessible(true);
//设置maxKeySize的值为257,257>256
cryptoPermField.set(cryptoPerm,257);
}catch (Exception e){
e.printStackTrace();
}
}
/**
* 私钥签名
* @param content
* @param privateKey
* @return
*/
public static byte[] sign(String content,ECPrivateKey privateKey) throws Exception {
Signature signature = Signature.getInstance(SIGNATURE);
signature.initSign(privateKey);
signature.update(content.getBytes());
return signature.sign();
}
/**
* 公钥验签
* @param content
* @param sign
* @param publicKey
* @return
* @throws Exception
*/
public static boolean verify(String content,byte[] sign,ECPublicKey publicKey) throws Exception{
Signature signature = Signature.getInstance(SIGNATURE);
signature.initVerify(publicKey);
signature.update(content.getBytes());
return signature.verify(sign);
}
/**
* 解析证书的签名算法,单独一本公钥或者私钥是无法解析的,证书的内容远不止公钥或者私钥
* @param certFile
* @return
* @throws Exception
*/
private static String getSignature(File certFile) throws Exception{
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME);
X509Certificate x509Certificate = (X509Certificate) certificateFactory.generateCertificate(new FileInputStream(certFile));
return x509Certificate.getSigAlgName();
}
public static void main(String[] args){
try{
ECKeyPair keyPair = generateKeyPair();
//生成公钥和私钥对象
String publicKey = keyPair.getPublicKey();
String privateKey = keyPair.getPrivateKey();
//生成一个Base64编码的公钥字符串,可用来传输
System.out.println("[publickey]:\t" + publicKey);
System.out.println("[privateKey]:\t" + privateKey);
String publicKey2 = "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAVTvWXj54VDU7gsZ1qUbgoodXcdSfLJ0gKdYz6V8UBMRgQ3hXZQuMgd2EtXYhus896DRqlGwZnkGje6OD9vGqw==";
String privateKey2 = "MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgkBo4mH179XUS1Zx45UJVk2El5zXJf5wdfGwZVlbMSPKgCgYIKoZIzj0DAQehRANCAAQBVO9ZePnhUNTuCxnWpRuCih1dx1J8snSAp1jPpXxQExGBDeFdlC4yB3YS1diG6zz3oNGqUbBmeQaN7o4P28ar";
//测试文本
String content = "SM2是国家密码管理局于2010年12月17日发布的椭圆曲线公钥密码算法。该算法是一种基于ECC算法的非对称密钥算法,其加密强度为256位,其安全性与目前使用的RSA1024相比具有明显的优势。SM2算法和RSA算法都是公钥密码算法,SM2算法是一种更先进安全的算法,在我们国家商用密码体系中被用来替换RSA算法。随着密码技术和计算机技术的发展,目前常用的1024位RSA算法面临严重的安全威胁,我们国家密码管理部门经过研究,决定采用SM2椭圆曲线算法替换RSA算法。";
//加密
String cipherTxt=encrypt(publicKey2, content);
System.out.println("content: "+content);
System.out.println("cipherTxt: "+cipherTxt);
//解密,此字符串可用来网络传输
String cipherString = cipherTxt;
String clearTxt=decrypt(privateKey2, cipherString);
System.out.println("clearTxt:"+new String(clearTxt));
}catch (Exception e){
e.printStackTrace();
}
//printProvider();
}
/**
* RSA密钥对对象
*/
public static class ECKeyPair {
private final String publicKey;
private final String privateKey;
public ECKeyPair(String publicKey, String privateKey) {
this.publicKey = publicKey;
this.privateKey = privateKey;
}
public String getPublicKey() {
return publicKey;
}
public String getPrivateKey() {
return privateKey;
}
}
}
SM3实现
package tech.kunyuan.core.utils;
import org.bouncycastle.crypto.digests.SM3Digest;
import org.bouncycastle.crypto.macs.HMac;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
/**
* Description: 国密算法 SM3
* Author: ky
* DateTime: 2024-11-19 15:42
*/
public class Sm3Utils {
/**
* sm3算法加密,不可逆加密
* @param plainText 需加密的明文字符串
* @return 加密后固定长度64的16进制字符串
*/
public static String encrypt(String plainText) {
return ByteUtils.toHexString(encrypt(plainText.getBytes()));
}
/**
* sm3算法加密,不可逆加密
* @param plainByte 需加密的明文数组
* @return 加密后固定长度64的16进制数组
*/
public static byte[] encrypt(byte[] plainByte) {
SM3Digest sm3Digest = new SM3Digest();
sm3Digest.update(plainByte, 0, plainByte.length);
byte[] digestByte = new byte[sm3Digest.getDigestSize()];
sm3Digest.doFinal(digestByte, 0);
return digestByte;
}
/**
* sm3算法通过密钥进行加密,不可逆加密
* @param keyText 密钥字符串
* @param plainText 需加密的明文字符串
* @return 加密后固定长度64的16进制字符串
*/
public static String encryptByKey(String keyText, String plainText) {
return ByteUtils.toHexString(encryptByKey(keyText.getBytes(), plainText.getBytes()));
}
/**
* sm3算法通过密钥进行加密,不可逆加密
* @param keyByte 密钥数组
* @param plainByte 需加密的明文数组
* @return 加密后固定长度64的16进制数组
*/
public static byte[] encryptByKey(byte[] keyByte, byte[] plainByte) {
KeyParameter keyParameter = new KeyParameter(keyByte);
SM3Digest sm3Digest = new SM3Digest();
HMac hMac = new HMac(sm3Digest);
hMac.init(keyParameter);
hMac.update(plainByte, 0, plainByte.length);
byte[] result = new byte[hMac.getMacSize()];
hMac.doFinal(result, 0);
return result;
}
public static void main(String[] args){
String str = "1234AABBBDccc";
String result = encrypt(str);
System.out.println(result);
}
}
SM4实现:
package tech.kunyuan.core.utils;
import org.apache.commons.codec.binary.Hex;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Arrays;
/**
* Description: 国密算法 SM4
* Author: ky
* DateTime: 2024-11-18 17:28
*/
public class Sm4Utils {
private static final String ENCODING = "UTF-8";
public static final String ALGORITHM_NAME = "SM4";
// 加密算法/分组加密模式/分组填充方式
// PKCS5Padding-以8个字节为一组进行分组加密
// 定义分组加密模式使用:PKCS5Padding
public static final String ALGORITHM_NAME_ECB_PADDING = "SM4/ECB/PKCS5Padding";
// 128-32位16进制;256-64位16进制
public static final int DEFAULT_KEY_SIZE = 128;
static {
Security.addProvider(new BouncyCastleProvider());
}
/**
* 自动生成密钥
*
* @return
* @explain
*/
public static String generateKey() throws Exception {
return new String(Hex.encodeHex(generateKey(DEFAULT_KEY_SIZE),false));
}
/**
* @param keySize
* @return
* @throws Exception
* @explain
*/
public static byte[] generateKey(int keySize) throws Exception {
KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM_NAME, BouncyCastleProvider.PROVIDER_NAME);
kg.init(keySize, new SecureRandom());
return kg.generateKey().getEncoded();
}
/**
* 生成ECB暗号
*
* @param algorithmName 算法名称
* @param mode 模式
* @param key
* @return
* @throws Exception
* @explain ECB模式(电子密码本模式:Electronic codebook)
*/
private static Cipher generateEcbCipher(String algorithmName, int mode, byte[] key) throws Exception {
Cipher cipher = Cipher.getInstance(algorithmName, BouncyCastleProvider.PROVIDER_NAME);
Key sm4Key = new SecretKeySpec(key, ALGORITHM_NAME);
cipher.init(mode, sm4Key);
return cipher;
}
/**
* sm4加密
*
* @param hexKey 16进制密钥(忽略大小写)
* @param paramStr 待加密字符串
* @return 返回16进制的加密字符串
* @explain 加密模式:ECB
* 密文长度不固定,会随着被加密字符串长度的变化而变化
*/
public static String encrypt(String hexKey, String paramStr) {
try {
String cipherText = "";
// 16进制字符串-->byte[]
byte[] keyData = ByteUtils.fromHexString(hexKey);
// String-->byte[]
byte[] srcData = paramStr.getBytes(ENCODING);
// 加密后的数组
byte[] cipherArray = encryptPadding(keyData, srcData);
// byte[]-->hexString
cipherText = ByteUtils.toHexString(cipherArray);
return cipherText;
} catch (Exception e) {
return paramStr;
}
}
/**
* sm4加密
*
* @param hexKey 16进制密钥(忽略大小写)
* @param paramStr 待加密字符串
* @return 返回16进制的加密字符串
* @explain 加密模式:ECB
* 密文长度不固定,会随着被加密字符串长度的变化而变化
*/
public static String encrypt(byte[] hexKey, String paramStr) {
try {
String cipherText = "";
// 16进制字符串-->byte[]
byte[] keyData = hexKey;
// String-->byte[]
byte[] srcData = paramStr.getBytes(ENCODING);
// 加密后的数组
byte[] cipherArray = encryptPadding(keyData, srcData);
// byte[]-->hexString
cipherText = ByteUtils.toHexString(cipherArray);
return cipherText;
} catch (Exception e) {
return paramStr;
}
}
/**
* 加密模式之Ecb
*
* @param key
* @param data
* @return
* @throws Exception
* @explain
*/
public static byte[] encryptPadding(byte[] key, byte[] data) throws Exception {
Cipher cipher = generateEcbCipher(ALGORITHM_NAME_ECB_PADDING, Cipher.ENCRYPT_MODE, key);
return cipher.doFinal(data);
}
/**
* sm4解密
*
* @param hexKey 16进制密钥
* @param cipherText 16进制的加密字符串(忽略大小写)
* @return 解密后的字符串
* @throws Exception
* @explain 解密模式:采用ECB
*/
public static String decrypt(String hexKey, String cipherText) {
// 用于接收解密后的字符串
String decryptStr = "";
// hexString-->byte[]
byte[] keyData = ByteUtils.fromHexString(hexKey);
// hexString-->byte[]
byte[] cipherData = ByteUtils.fromHexString(cipherText);
// 解密
byte[] srcData = new byte[0];
try {
srcData = decryptPadding(keyData, cipherData);
// byte[]-->String
decryptStr = new String(srcData, ENCODING);
} catch (Exception e) {
//log.error(ExceptionUtil.getMessage(e));
}
return decryptStr;
}
/**
* 解密
*
* @param key
* @param cipherText
* @return
* @throws Exception
* @explain
*/
public static byte[] decryptPadding(byte[] key, byte[] cipherText) throws Exception {
Cipher cipher = generateEcbCipher(ALGORITHM_NAME_ECB_PADDING, Cipher.DECRYPT_MODE, key);
return cipher.doFinal(cipherText);
}
/**
* 校验加密前后的字符串是否为同一数据
*
* @param hexKey 16进制密钥(忽略大小写)
* @param cipherText 16进制加密后的字符串
* @param paramStr 加密前的字符串
* @return 是否为同一数据
* @throws Exception
* @explain
*/
public static boolean verifyEcb(String hexKey, String cipherText, String paramStr) throws Exception {
// 用于接收校验结果
boolean flag = false;
// hexString-->byte[]
byte[] keyData = ByteUtils.fromHexString(hexKey);
// 将16进制字符串转换成数组
byte[] cipherData = ByteUtils.fromHexString(cipherText);
// 解密
byte[] decryptData = decryptPadding(keyData, cipherData);
// 将原字符串转换成byte[]
byte[] srcData = paramStr.getBytes(ENCODING);
// 判断2个数组是否一致
flag = Arrays.equals(decryptData, srcData);
return flag;
}
public static void main(String[] args){
try {
String key = "9B9B384162676DA830510247D09EB0C2";//generateKey();
System.out.println(key);
String str = "SM2是国家密码管理局于2010年12月17日发布的椭圆曲线公钥密码算法。该算法是一种基于ECC算法的非对称密钥算法,其加密强度为256位,其安全性与目前使用的RSA1024相比具有明显的优势。SM2算法和RSA算法都是公钥密码算法,SM2算法是一种更先进安全的算法,在我们国家商用密码体系中被用来替换RSA算法。随着密码技术和计算机技术的发展,目前常用的1024位RSA算法面临严重的安全威胁,我们国家密码管理部门经过研究,决定采用SM2椭圆曲线算法替换RSA算法。";
String result = encrypt(key, str);
System.out.println(result);
String result2 = decrypt(key, result);
System.out.println(result2);
}
catch (Exception e) {
}
}
}
JS
// 安装 sm-crypto
yarn add sm-crypto
或
npm install sm-crypto
SM2
import sm from 'sm-crypto'
const keypair = sm.sm2.generateKeyPairHex()
const publicKey = keypair.publicKey
const privateKey = keypair.privateKey
const text = 'hello world'
// 1-C1C3C2, 0-C1C2C2
const cipherMode = 1
const encryptData = sm.sm2.doEncrypt(text, publicKey, cipherMode)
const decryptData = sm.sm2.doDecrypt(encryptData, privateKey, cipherMode)
console.log(encryptData + '++++' + decryptData)
SM3
import sm from 'sm-crypto'
const text = 'hello world'
const encryptData = sm.sm3(text)
console.log(encryptData)
SM4
import sm from 'sm-crypto'
// 密钥
const secret = '0123456789abcdefg...'
// 设置SM4加解密模式(ecb、cbc、ctr等)
const mode = 'cbc'
const text = 'hello world'
// 加密数据
const encryptData = sm.sm4.encrypt(text, key, { mode });
// 解密数据
const decryptData = sm.sm4.decrypt(encryptData, key, { mode });
console.log(encryptData + '++++' + decryptData)
Python
pip3 install gmssl
SM2
SM3
from gmssl import sm3, func
text = b'hello world'
print(sm3.sm3_hash(func.bytes_to_list(text)))
SM4
from gmssl import sm4, func
sm4_crypt = sm4.CryptSM4()
key = b'0123456789ABCDEF0123456789ABCDEF'
sm4_crypt.set_key(key, sm4.SM4_ENCRYPT)
text = b'hello world'
# 加密
cipherText = sm4_crypt.crypt_ecb(func.bytes_to_list(text))
cipherData = bytes(func.list_to_bytes(cipherText))
print(cipherText, cipherData.hex())
# 解密
sm4_crypt.set_key(key, sm4.SM4_DECRYPT)
decryptData = sm4_crypt.crypt_ecb(cipherText)
print(decryptData.decode('utf-8'))