工欲善其事,必先利其器。一个好用的调试工具不仅能降低重复的劳动还要减少不必要的弯路以提高工作效率。在国密算法的应用项目中,笔者前前后后下载体验过不少桌面工具、密码算法库和浏览器在线工具,在这里分享几个用起来不错的工具。想要得心应手的使用工具,还需要对国密算法有一定的了解,在这个章节也会对算法做一个简单的介绍。
2.1、SM2/SM3/SM4算法介绍
为了便于后续的理解,在这里向大家分享介绍下笔者对商密算法标准规范文档中的一些理解。对于普通的软件密钥,在签名验签、加密解密时,参考GM/T_0009规范;如果是硬件密钥,商密产品类别为智能密码钥匙请参考GM/T_00016规范(SKF接口),商密产品类别为智能密码设备则参考GM/T_00018规范(SDF接口)。特别是在涉及到软件密钥和硬件密钥交互时,尤其需要注意规范问题。
相关密码行业参考标准:
部分标准已上升为国家标准如下:
2.1.1、基本概念
笔者在这里只介绍几个重要概念和关键点,并不涉及具体的算法实现,对算法实现过程感兴趣的话可以参阅标准规范进一步学习。
SM2算法:SM2算法全称是SM2椭圆曲线公钥密码算法(SM是商用密码的缩写),是一种基于“椭圆曲线”的密码ECC。2016年,SM2成为中国国家密码标准。在商用密码体系中,SM2主要用于替换RSA算法。
简单的说,SM2密钥对的生成是基于椭圆曲线算法的,私钥是一个随机数,公钥是椭圆曲线上的一个点(x,y),即公钥由x和y分量组成。
椭圆曲线:在《SM2椭圆曲线公钥密码算法第1部分:总则》中,介绍了两种椭圆曲线,一种是定义在Fp上的椭圆曲线方程,其中Fp是指包含p个元素的素域,所以又称之为素域曲线;另一种是定义在F2m上的椭圆曲线方程,其中F2m是指包含2m个元素的二元扩域。在《SM2椭圆曲线公钥密码算法第5部分:参数定义》中, 明确定义了SM2使用素数域256位椭圆曲线,并给出了椭圆曲线方程式(y2=x3+ax+b)和默认曲线参数值(p、a、b、n、xG、yG)。
注意:在前后端的SM2加解密和签名验签交互中,请确认双方使用的密码运算库的椭圆曲线参数一致,否则会导致联调失败。
预处理:在《SM2密码算法使用规范》中,介绍了预处理1和预处理2两个过程。预处理1是指使用签名方的用户身份标识和签名方公钥,通过运算得到Z值的过程。Z值的计算需要输入用户身份标识ID和公钥,用户身份标识ID的数据类型为字节串,国密标准里用户身份标识ID的缺省值是“1234567812345678”。预处理2是指使用Z值和待签名消息,通过SM3运算得杂凑值H的过程。
注意:Z值的计算需要用到用户身份标识ID,可以理解为签名者ID。在前后端的SM2签名验签交互中,如果双方ID不一致,那么也会导致联调失败。
2.1.2、SM2密钥数据格式
标准规范中关于SM2密钥数据格式的定义如下:
SM2算法公钥数据格式定义:
补充说明:SM2算法的私钥数据长度为32字节,SM2算法的公钥数据长度为64字节,其中X分量和Y分量分别为32字节。注意,在导入/导出公钥至安全芯片时,只需要64字节的公钥,而不需要“04”标识符。
2.1.3、SM2加密数据格式
标准规范中关于SM2加密数据格式的定义如下:
补充说明:SM2加密的结果由C1、C2、C3三部分组成。其中,C1是是椭圆曲线上的点,包括32字节x分量和32字节y分量;C2是密文数据,长度与明文一致;C3是杂凑值,长度固定为32字节。在旧的国密标准里,SM2加密结果是按照C1||C2||C3排序存放,新标准则是按照C1||C3||C2排序存放。据笔者所知,BC库默认使用的排序方式是C1||C2||C3,在前后端的加解密应用中,需要注意这一点,
2.1.4、SM2签名数据格式
标准规范中关于SM2签名数据格式的定义如下:
补充说明:签名数据格式没有需要特别注意的地方,仅需要考虑软件算法时的补零问题即可。
2.1.5、SM3密码杂凑算法
SM3密码杂凑算法是中国国家密码管理局2010年公布的中国商用密码杂凑算法标准。该算法于2012年发布为密码行业标准(GM/T 0004-2012),2016年发布为国家密码杂凑算法标准(GB/T 32905-2016)。
标准规范中关于SM3密码杂凑算法的描述如下:
2.1.6、SM4分组密码算法
SM4分组密码算法是由中国国家密码管理局于2012年发布为密码行业标准(GM/T 0002-2012),2016年成为中国国家密码标准(GB/T 32907-2016)。
对称密码有两种主要形式:一是序列密码(也称“流密码”,stream cipher),典型的如我国的祖冲之密码算法ZUC;二是分组密码(也称”块密码”,block cipher),典型的如我国的SM4算法。两者的区别不再赘述,后续介绍以SM4算法为主。
在《GB/T 17964-2008 信息安全技术 分组密码算法的工作模式》国家标准中,根据分组数据块链接的组合模式不同,分组密码算法可以分为其中工作模式:电码本模式(ECB)、密文分组链接模式(CBC)、密文反馈模式(CFB)、输出反馈模式(OFB)、计数器模式(CTR)、分组链接模式(BC)和带非线性函数的输出反馈模式(OFBNLF),其中ECB、CBC、CTR三种模式比较常用。
在标准规范中关于SM4算法数据结构的描述如下:
补充说明:可以看到SM4算法涉及到消息分组问题,当待加密数据长度小于16Byte时,我们就需要使用填充算法保证待加密消息长度为16Byte的整数倍。加密前填充数据,解密后删除填充数据。常见的填充方式有ZeroPadding、PKCS7Padding和PKCS5Padding等。JAVA平台使用的BC库支持的填充模式如下:
2.2、PC小工具
2.2.1、ASN.1 Editor
ASN.1 Editor是一个能够显示、编辑、格式化和转换ASN.1编码数据的工具。该工具需要.NET Framework4.5依赖包。
ASN.1 Editor在项目中主要用来分析和提取数字证书中的数据。在《GMT 0015-2012 基于SM2密码算法的数字证书格式规范》中,对采用SM2算法的数字证书做了说明,如下所示为数字证书的基本数据结构:
数字证书包含三个域,tbsCertificate是to be signed Certificate的缩写,笔者在这里称之为待签名证书,它是指被CA机构私钥签名的用户证书;signatureAlgorithm是指所签名算法标识;signatureValue是指签名值,它是被CA机构使用私钥对整个tbsCertificate域进行数字签名的结果。下面给出一个图示:
图中括号(x,y)的含义是偏移量和域长度,偏移量是指相对与起始位置的绝对偏移量,域长度是指当前域的数据长度。在ASN.1Editor的View菜单下,选择”Hex Viewer”即可查看十六进制数据。至于数据结构中每个字段的具体含义,请参阅标准规范解读,这里不再赘述,以下给出一个PEM编码的由GmSSL算法库生成的证书内容图示:
在前面的基本概念中,我们提到SM2算法签名结果分别由256位R和S组成,但在这个图中你可以看到R值长度为33字节,这是因为R值的第一个数据“D8”的最高位为“1”,GmSSL算法库按照ASN.1编码规范在第一个数据前做了补零;而S值的第一个数据“48”的最高位为“0”,则不做处理。
DER编码证书文件可同样操作。原始数据、DER编码与PEM编码的转换关系如下图所示:
2.2.2、SmartTool
SmartTool是一款基于国家密码技术标准的加密算法工具集,不仅包含国密算法还包含国际标准密码算法,甚至还支持常见的数据转换和数据运算。
这个软件目前比较流行的版本是v1.3,发布于2012年,比较老了,所以在使用时需要注意国密算法的新特性。比如SM2算法加密后的数据格式,该工具默认的排序方式是C1||C2||C3,但是目前普遍采用新标准的C1||C3||C2的排序方式。使用时需要注意这一点,否则会导致解密失败。
2.2.3、VSCode
在VSCode中也能进行一部分密码分析工作,但是需要安装三个插件,分别为“Base64”、“x509 parser”和“ASN.1”,插件的使用方法见插件的细节说明。
这里给出一个基础用法示例,更多的操作读者可以按照插件说明自行研究。例如,使用VSCode打开一个pem编码证书,通过快捷键“Ctrl+Shift+P”打开命令面板,选择“Parse x509 certificate”分析509证书命令,结果如下所示:
2.3、密码运算库
在Linux平台下,我们只需安装好OpenSSL或者GMSSL密码算法库即可,算法库除了支持密码运算指令外,还包含用来分析ASN.1结构的asn1parse工具,并且支持在命令行中操作。下面通过使用GMSSL验证证书的完整性为例来分享笔者的使用心得。
2.3.1、使用GMSSL模拟SM2证书验证过程
验证的原理仍然是基于SM2签名/验签,需要从x.509证书中提取tbsCertificate待签名数据和signatureValue签名值以及签名私钥对应的公钥。可以通过asn1parse命令来提取证书中的待签名数据和签名值,关于asn1parse的用法可以通过命令行help产看也可以通过在线文档OpenSSL 中文手册 | OpenSSL 中文网 | 32.2 asn1parse来查阅。
补充说明:从证书中提取数据时需要注意“数据范围”,待签名数据是指整个tbsCertificate域,那么签名值呢?在标准规范中是这样描述的,
意思是签名结果R和S要按照ASN.1编码成BIT STRING类型并保存在证书签名值域内,再来看证书的数据结构:
其中,标号“1”是标准规范中描述的BIT STRING类型,而标号“2”是我们需要的签名值。那么它的长度是多少呢?并不是一个固定的值,长度在70~72之间。这是因为在经过ASN.1编码时,要对R和S可能做补零,这就多出了2字节;再加上ASN.1编码时添加的构造类型Tag和长度Length,R和S各自需要添加2字节Tag-Len,在组成Sequence序列时又需要添加2字节Tag-Len。R和S的总长度为64字节,在R和S都需要补零的情况下,长度就是72字节;在R和S都不需要补零的情况下,长度就是70字节。需要注意的是,当使用硬件芯片验签时,签名值是由R和S组成的固定的64字节值。
第一步,我们先使用asn1parse命令来分析数字证书的数据结构,获取tbsCertificate序列和signatureValue序列的偏移量。这里以“clientca.pem”证书文件为例来说明:
可以看到,使用asn1parse命令来解析不够直观,我们改为使用ASN.1Editor工具来辅助分析就很直观了,如下图所示:
第二步,从证书中提取待签名数据tbsCertificate,如下图所示:
参数“-strparse 4”表示从偏移量4开始分析一段Sequence数据。
第三步,从证书中提取tbsValue签名值,如下图所示:
第四步,使用待签名数据、签名值、验签公钥和签名ID来验签。假设签名密钥对的公钥文件为“root_pub.key”,签名时使用的ID为默认的“1234567812345678”,验签命令如下:
至此,一个简单的X.509证书模拟验证过程就完成了。万变不离其宗,再复杂的签名验签过程也是以此为基础展开的。
2.3.2、JAVA BC库联调重点记录
前面提到的SM2验签问题,还需要注意一点,当使用OpenSSL/GMSSL库对接JAVA BC库时发现双方签名验签时,不一定能通过,这是由于BC库里签名默认内部计算Z值,而GMSSL的签名默认不计算Z值。笔者在项目中使用GMSSLv2.5.4版本时这个问题仍然存在。另外,BC库在导入外部公钥时,一定要在公钥前“04”标识,如果公钥不是以04开头,会报“Invalid point encoding 77”错误。
另外一个有意思的事情是,在使用BC库生成P10请求证书时,我们可以分别组织证书请求信息Info、签名算法和签名值来生成CSR文件。这在和安全芯片结合的电子印章交互过程中很实用。
2.4、浏览器在线工具
2.4.1、THE-X在线工具箱-web访问
地址:The-X 在线工具箱 Base64 解码 AES RAS 解码 加密
the-x在线工具箱提供base64编解码、AES/DES/RSA加解密、SM2/SM4加解密等等功能,我们主要使用它的SM2/SM4加解密功能。需要注意这个在线工具箱SM4加密的默认填充方式是ZeroPadding,如果采用其他的填充方式请注意这一点。
2.4.2、LZL在线工具-web访问
LZL在线工具提供了更多的可配置选项,相比The-X工具更加的灵活,当然了,前期是你要理解它的每个配置参数的含义。
2.5、其他工具
当然了,还有其他很多工具,比如与ASN.1 Editor比较相似的PC小工具asn1dump,在线SM2/SM4工具集(工具列表),以及Windows下的Win64OpenSSL安装包等等,由于精力和篇幅所限,笔者不再一一介绍,感兴趣的读者可自行探索研究。
Win64OpenSSL安装包下载地址:
Win32/Win64 OpenSSL Installer for Windows - Shining Light Productions
2.6、总结
在实际的项目中,笔者最终选择了GMSSL算法库、ASN.1Editor和The-X作为最终的开发辅助工具,读者可借鉴参考。
备注:为了方便下载,文章中提到的工具做了汇总,传送门:国密技术应用开发工具集