一文搞懂国密SM加密(VIP典藏版)

warning: 这篇文章距离上次修改已过302天,其中的内容可能已经有所变动。

一、前言
加密概述

国密算法是我国自主研发创新的一套数据加密处理系列算法。从SM1-SM4分别实现了对称、非对称、摘要等算法功能。特别适合应用于嵌入式物联网等相关领域,完成身份认证和数据加解密等功能。当然,默认的前提条件是算法密钥必须保证安全性,因此要将国密算法嵌入到硬件加密芯片中结合使用。

加密是通过“加密算法”将明文加密成密文,可以通过“密钥”和“解密算法”将密文还原成明文。
密码学中应用最为广泛的三类算法:

国密算法,即国家商用密码算法。是由国家密码管理局认定和公布的密码算法标准及其应用规范,其中部分密码算法已经成为国际标准。如SM系列密码,SM代表商密,即商业密码,是指用于商业的、不涉及国家秘密的密码技术。

商用密码有很多,作为一览,我整理出下表,列举了常用的国际跟国产商密:

对称算法(分组密码算法):AES/DES/3DES/SM4/SM4

用途:对称加密算法用来对敏感数据等信息进行加密

SM1 为对称加密。其加密强度与AES相当。该算法不公开,调用该算法时,需要通过加密芯片的接口进行调用。
非对称算法(公钥密码算法):RSA/DSA/ECC/SM2

SM2为非对称加密,基于ECC。
RSA:由 RSA 公司发明,是一个支持变长密钥的公共密钥算法,需要加密的文件块的长度也是可变的。RSA在国外早已进入实用阶段,已研制出多种高速的RSA的专用芯片。

DSA(Digital Signature Algorithm):数字签名算法,是一种标准的 DSS(数字签名标准),严格来说不算加密算法。

ECC(Elliptic Curves Cryptography):椭圆曲线密码编码学。ECC和RSA相比,具有多方面的绝对优势,主要有:抗攻击性强。相同的密钥长度,其抗攻击性要强很多倍。计算量小,处理速度快。ECC总的速度比RSA、DSA要快得多。存储空间占用小。ECC的密钥尺寸和系统参数与RSA、DSA相比要小得多,意味着它所占的存贮空间要小得多。这对于加密算法在IC卡上的应用具有特别重要的意义。带宽要求低。当对长消息进行加解密时,三类密码系统有相同的带宽要求,但应用于短消息时ECC带宽要求却低得多。带宽要求低使ECC在无线网络领域具有广泛的应用前景。
摘要算法(杂凑算法):MD5/SHA-I/SM3

SM3消息摘要。可以用MD5作为对比理解。该算法已公开。校验结果为256位。

MD5、SHA1、HMAC
用途:主要用于验证,防止信息被修。具体用途如:文件校验、数字签名、鉴权协议。

哈希算法也称摘要算法,是指把可变长度的数据通过运算得到固定长度散列值的不可逆算法,只要原始数据稍微改动得到的散列值机会完全不同,因为这个特性,哈希算法通常应用于对数据的完整性校验以及密码验证。

常见的哈希算法有MD5、SHA1、SHA256、SHA512、NTLM等。
国密算法的意义

随着金融安全上升到国家安全高度,近年来国家有关机关和监管机构站在国家安全和长远战略的高度提出了推动国密算法应用实施、加强行业安全可控的要求。摆脱对国外技术和产品的过度依赖,建设行业网络安全环境,增强我国行业信息系统的“安全可控”能力显得尤为必要和迫切。
密码算法是保障信息安全的核心技术,尤其是最关键的银行业核心领域长期以来都是沿用3DES、SHA-1、RSA、AES等国际通用的密码算法体系及相关标准。2010年底,国家密码管理局公布了我国自主研制的“椭圆曲线公钥密码算法”(SM2算法)。为保障重要经济系统密码应用安全,国家密码管理局于2011年发布了《关于做好公钥密码算法升级工作的通知》,要求“自2011年3月1日起,在建和拟建公钥密码基础设施电子认证系统和密钥管理系统应使用国密算法。自2011年7月1日起,投入运行并使用公钥密码的信息系统,应使用SM2算法。”
二、国密算法
SM1是一种分组加密算法

对称加密算法中的分组加密算法,其分组长度、秘钥长度都是128bit,算法安全保密强度跟 AES 相当,但是算法不公开,仅以IP核的形式存在于芯片中,需要通过加密芯片的接口进行调用。

采用该算法已经研制了系列芯片、智能IC卡、智能密码钥匙、加密卡、加密机等安全产品,广泛应用于电子政务、电子商务及国民经济的各个应用领域(包括国家政务通、警务通等重要领域)。
SM2是非对称加密算法

它是基于椭圆曲线密码的公钥密码算法标准,其秘钥长度256bit,包含数字签名、密钥交换和公钥加密,用于替换RSA/DH/ECDSA/ECDH等国际算法。可以满足电子认证服务系统等应用需求,由国家密码管理局于2010年12月17号发布。

SM2采用的是ECC 256位的一种,其安全强度比RSA 2048位高,且运算速度快于RSA。
SM3是一种密码杂凑算法

用于替代MD5/SHA-1/SHA-2等国际算法,适用于数字签名和验证、消息认证码的生成与验证以及随机数的生成,可以满足电子认证服务系统等应用需求,于2010年12月17日发布。

它是在SHA-256基础上改进实现的一种算法,采用Merkle-Damgard结构,消息分组长度为512bit,输出的摘要值长度为256bit。
SM4是分组加密算法

跟SM1类似,是我国自主设计的分组对称密码算法,用于替代DES/AES等国际算法。SM4算法与AES算法具有相同的密钥长度、分组长度,都是128bit。于2012年3月21日发布,适用于密码应用中使用分组密码的需求。
SM7也是一种分组加密算法

该算法没有公开。SM7适用于非接IC卡应用包括身份识别类应用(门禁卡、工作证、参赛证),票务类应用(大型赛事门票、展会门票),支付与通卡类应用(积分消费卡、校园一卡通、企业一卡通、公交一卡通)。
SM9是基于标识的非对称密码算法

用椭圆曲线对实现的基于标识的数字签名算法、密钥交换协议、密钥封装机制和公钥加密与解密算法,包括数字签名生成算法和验证算法,并给出了数字签名与验证算法及其相应的流程。并提供了相应的流程。可以替代基于数字证书的PKI/CA体系。

SM9主要用于用户的身份认证。据新华网公开报道,SM9的加密强度等同于3072位密钥的RSA加密算法,于2016年3月28日发布。
三、国密算法的安全性

国密即国家密码局认定的国产密码算法。主要有SM1,SM2,SM3,SM4。密钥长度和分组长度均为128位。

由于SM1、SM4加解密的分组大小为128bit,故对消息进行加解密时,若消息长度过长,需要进行分组,要消息长度不足,则要进行填充。

SM2算法:SM2椭圆曲线公钥密码算法是我国自主设计的公钥密码算法,包括SM2-1椭圆曲线数字签名算法,SM2-2椭圆曲线密钥交换协议,SM2-3椭圆曲线公钥加密算法,分别用于实现数字签名密钥协商和数据加密等功能。SM2算法与RSA算法不同的是,SM2算法是基于椭圆曲线上点群离散对数难题,相对于RSA算法,256位的SM2密码强度已经比2048位的RSA密码强度要高。

SM3算法:SM3杂凑算法是我国自主设计的密码杂凑算法,适用于商用密码应用中的数字签名和验证消息认证码的生成与验证以及随机数的生成,可满足多种密码应用的安全需求。为了保证杂凑算法的安全性,其产生的杂凑值的长度不应太短,例如MD5输出128比特杂凑值,输出长度太短,影响其安全性。SHA-1算法的输出长度为160比特,SM3算法的输出长度为256比特,因此SM3算法的安全性要高于MD5算法和SHA-1算法。

SM4算法:SM4分组密码算法是我国自主设计的分组对称密码算法,用于实现数据的加密/解密运算,以保证数据和信息的机密性。要保证一个对称密码算法的安全性的基本条件是其具备足够的密钥长度,SM4算法与AES算法具有相同的密钥长度分组长度128比特,因此在安全性上高于3DES算法。

随着国密算法推广的延伸,金融领域引入SM2、SM3、SM4等算法逐步替换原有的RSA、ECC等国外算法。现有银联银行卡联网、银联IC两项规范都引入了国密算法相关要求。如下图所示为金融活动中会应用到国密算法的业务。


四、加密算法安全性比较

SM2和RSA

256位的SM2>2048位的RSA

SM3/MD5/SHA-1

MD5输出长度128bit
SHA-1输出长度160bit
SM3输出长度256bit
输出长度越长,安全性越高,所以SM3>SHA-1>MD5

SM4/AES/3DES

对称加密算法用于实现数据的加密和解密运算。要保证一个对称加密算法的安全性的基本条件是其具备氹的密钥长度,SM4密钥长度为128bit,分组长度为128bit。

所以安全性:SM4>AES>3DES

国密算法也不完全是安全的,对算法的攻击,一种常见的手段是SCA(side channel attack,边信道攻击)。RSA/AES/DES都可以被攻破,SM2/SM4也一样。
所以金融领域的产品,特别是银行的移动端产品,都要求必须经过算法的安全认证,那么带有独立算法引擎的安全硬件--加密机就非常重要了。也就是银行中的密管平台系统。
五、代码应用
依赖

<dependency>
    <groupId>com.antherd</groupId>
    <artifactId>sm-crypto</artifactId>
    <version>0.3.2</version>
</dependency>

sm2
获取密钥对

Keypair keypair = Sm2.generateKeyPairHex();
String privateKey = keypair.getPrivateKey(); // 公钥
String publicKey = keypair.getPublicKey(); // 私钥

加密解密

// cipherMode 1 - C1C3C2,0 - C1C2C3,默认为1
String encryptData = Sm2.doEncrypt(msg, publicKey); // 加密结果
String decryptData = Sm2.doDecrypt(encryptData, privateKey); // 解密结果

签名验签

ps:理论上来说,只做纯签名是最快的。

// 纯签名 + 生成椭圆曲线点
String sigValueHex = Sm2.doSignature(msg, privateKey); // 签名
boolean verifyResult = Sm2.doVerifySignature(msg, sigValueHex, publicKey); // 验签结果
 
// 纯签名
Queue<Point> pointPool = new LinkedList(Arrays.asList(Sm2.getPoint(), Sm2.getPoint(), Sm2.getPoint(), Sm2.getPoint()));
SignatureOptions signatureOptions2 = new SignatureOptions();
signatureOptions2.setPointPool(pointPool); // 传入事先已生成好的椭圆曲线点,可加快签名速度
String sigValueHex2 = Sm2.doSignature(msg, privateKey, signatureOptions2);
boolean verifyResult2 = Sm2.doVerifySignature(msg, sigValueHex2, publicKey); // 验签结果
 
// 纯签名 + 生成椭圆曲线点 + der编解码
SignatureOptions signatureOptions3 = new SignatureOptions();
signatureOptions3.setDer(true);
String sigValueHex3 = Sm2.doSignature(msg, privateKey, signatureOptions3); // 签名
boolean verifyResult3 = Sm2.doVerifySignature(msg, sigValueHex3, publicKey, signatureOptions3); // 验签结果
 
// 纯签名 + 生成椭圆曲线点 + sm3杂凑
SignatureOptions signatureOptions4 = new SignatureOptions();
signatureOptions4.setHash(true);
String sigValueHex4 = Sm2.doSignature(msg, privateKey, signatureOptions4); // 签名
boolean verifyResult4 = Sm2.doVerifySignature(msg, sigValueHex4, publicKey, signatureOptions4); // 验签结果
 
// 纯签名 + 生成椭圆曲线点 + sm3杂凑(不做公钥推导)
SignatureOptions signatureOptions5 = new SignatureOptions();
signatureOptions5.setHash(true);
signatureOptions5.setPublicKey(publicKey); // 传入公钥的话,可以去掉sm3杂凑中推导公钥的过程,速度会比纯签名 + 生成椭圆曲线点 + sm3杂凑快
String sigValueHex5 = Sm2.doSignature(msg, privateKey, signatureOptions5); // 签名
boolean verifyResult5 = Sm2.doVerifySignature(msg, sigValueHex5, publicKey, signatureOptions5); // 验签结果
 
// 纯签名 + 生成椭圆曲线点 + sm3杂凑 + 不做公钥推 + 添加 userId(长度小于 8192)
// 默认 userId 值为 1234567812345678
SignatureOptions signatureOptions6 = new SignatureOptions();
signatureOptions6.setHash(true);
signatureOptions6.setPublicKey(publicKey);
signatureOptions6.setUserId("testUserId");
String sigValueHex6 = Sm2.doSignature(msg, privateKey, signatureOptions6); // 签名
boolean verifyResult6 = Sm2.doVerifySignature(msg, sigValueHex6, publicKey, signatureOptions6); // 验签结果

获取椭圆曲线点

Point point = Sm2.getPoint(); // 获取一个椭圆曲线点,可在sm2签名时传入

sm3

String hashData = Sm3.sm3("abc"); // 杂凑

sm4
加密

String msg = "hello world! 我是 antherd.";
String key = "0123456789abcdeffedcba9876543210"; // 16 进制字符串,要求为 128 比特
 
String encryptData1 = Sm4.encrypt(msg, key); // 加密,默认使用 pkcs#5 填充,输出16进制字符串
 
Sm4Options sm4Options2 = new Sm4Options();
sm4Options2.setPadding("none");
String encryptData2 = Sm4.encrypt(msg, key, sm4Options2); // 加密,不使用 padding,输出16进制字符串
 
Sm4Options sm4Options3 = new Sm4Options();
sm4Options3.setPadding("none");
byte[] encryptData3 = Sm4.hexToBytes(Sm4.encrypt(msg, key, sm4Options3)); // 加密,不使用 padding,输出转为字节数组
 
Sm4Options sm4Options4 = new Sm4Options();
sm4Options4.setMode("cbc");
sm4Options4.setIv("fedcba98765432100123456789abcdef");
String encryptData4 = Sm4.encrypt(msg, key, sm4Options4); // 加密,cbc 模式,输出16进制字符串

解密

String encryptData = "0e395deb10f6e8a17e17823e1fd9bd98a1bff1df508b5b8a1efb79ec633d1bb129432ac1b74972dbe97bab04f024e89c"; // 加密后的 16 进制字符串
String key = "0123456789abcdeffedcba9876543210"; // 16 进制字符串,要求为 128 比特
 
String decryptData5 = Sm4.decrypt(encryptData, key); // 解密,默认使用 pkcs#5 填充,输出 utf8 字符串
 
Sm4Options sm4Options6 = new Sm4Options();
sm4Options6.setPadding("none");
String decryptData6 = Sm4.decrypt(encryptData, key, sm4Options6); // 解密,不使用 padding,输出 utf8 字符串
 
Sm4Options sm4Options7 = new Sm4Options();
sm4Options7.setPadding("none");
byte[] decryptData7 = Sm4.utf8ToArray(Sm4.decrypt(encryptData, key, sm4Options7)); // 解密,不使用 padding,输出转为字节数组
 
Sm4Options sm4Options8 = new Sm4Options();
sm4Options8.setMode("cbc");
sm4Options8.setIv("fedcba98765432100123456789abcdef");
String decryptData8 = Sm4.decrypt(encryptData, key, sm4Options8); // 解密,cbc 模式,输出 utf8 字符串

六、参考资料

GitHub - xjfuuu/SM2_SM3_SM4Encrypt: 基于Java语言的国密SM2/SM3/SM4算法库 , 包含加密/解密、签名/验签、摘要算法的实现代码和测试方法 。

国密算法介绍 - 知乎

国密加密算法 - chizz - 博客园

加密算法(国密算法)_后觉1992的博客-CSDN博客_国密加密算法

前后端组合加解密使用案例将在下期进行分享!
————————————————
版权声明:本文为CSDN博主「慕白Lee」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/libusi001/article/details/126532269

版权声明 ▶ 本网站名称:我的学习笔记
▶ 本文链接:https://ooolo.net/article/309.html
▶ 本网站的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,请联系站长进行核实删除。
▶ 转载本站文章需要遵守:商业转载请联系站长,非商业转载请注明出处!!!

none
最后修改于:2023年08月16日 15:20

添加新评论

icon_mrgreen.pngicon_neutral.pngicon_twisted.pngicon_arrow.pngicon_eek.pngicon_smile.pngicon_confused.pngicon_cool.pngicon_evil.pngicon_biggrin.pngicon_idea.pngicon_redface.pngicon_razz.pngicon_rolleyes.pngicon_wink.pngicon_cry.pngicon_surprised.pngicon_lol.pngicon_mad.pngicon_sad.pngicon_exclaim.pngicon_question.png