国密算法介绍

国密算法是指中国自主设计和使用的密码算法标准,其目的是保障信息安全和国家利益。

国密算法包括以下几个主要的密码算法:

算法名称类别应用领域特點
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性能更优更安全:密码复杂度高、处理速度快、机器性能消耗更小。

SM2RSA
算法结构基本椭圆曲线(ECC)基于特殊的可逆模幂运算
计算复杂度完全指数级亚指数级
存储空间192-256bit2048-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国密算法的安全特性

  1. 真随机数发生器
  2. 采用SM7国密算法加密保护数据交互的安全
  3. 采用SM7国密算法三重相互安全认证机制
  4. 具有8个相互独立的128位密码,支持一卡一密和一卡多用
  5. 每张卡具有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签名不可逆
算法名称秘钥长度
SM2256位(64位16进制数)
SM2签名256位(64位16进制数)
SM3签名
SM4128位(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'))
This entry was posted in 默认. Bookmark the permalink.