# 参考标准 * 《GB/T 32907-2016 信息安全技术 SM4分组密码算法》 * 《GB/T 17964-2021 信息安全技术 分组密码算法的工作模式》 您可以从[国家标准全文公开系统](https://openstd.samr.gov.cn/)在线阅读这些标准。 # 概述 SM4分组密码算法,其地位类似NIST中的AES分组密码算法,密钥长度128位(16字节),分组大小也是128位(16字节)。在本软件库中,SM4的实现与Go语言中的AES实现一致,也实现了```cipher.Block```接口,所以,所有Go语言中实现的工作模式(CBC/GCM/CFB/OFB/CTR),都能与SM4组合使用。 # 工作模式 在实际加解密操作中,我们一般不会直接使用```cipher.Block```,必须结合分组密码算法的工作模式使用。除了Go语言自带的工作模式(CBC/GCM/CFB/OFB/CTR),本软件库也实现了下列工作模式: * ECB - 电码本模式 * BC - 分组链接模式 * HCTR - 带泛杂凑函数的计数器模式 * XTS - 带密文挪用的XEX可调分组密码模式 * OFBNLF - 带非线性函数的输出反馈模式 * CCM - 分组密码链接-消息认证码组合模式 其中,ECB/BC/HCTR/XTS/OFBNLF是《GB/T 17964-2021 信息安全技术 分组密码算法的工作模式》列出的工作模式。BC/OFBNLF模式是商密中的遗留工作模式,**不建议**在新的应用中使用。XTS/HCTR模式适用于对磁盘加密,其中HCTR模式是《GB/T 17964-2021 信息安全技术 分组密码算法的工作模式》最新引入的,HCTR模式最近业界研究比较多,也指出了原论文中的Bugs:On modern processors HCTR [WFW05](https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.470.5288) is one of the most efficient constructions for building a tweakable super-pseudorandom permutation. However, a bug in the specification and another in Chakraborty and Nandi’s security proof [CN08](https://www.iacr.org/cryptodb/archive/2008/FSE/paper/15611.pdf) invalidate the claimed security bound. 不知道这个不足是否会影响到这个工作模式的采用。很奇怪《GB/T 17964-2021 信息安全技术 分组密码算法的工作模式》为何没有纳入GCM工作模式,难道是版权问题? 引入CCM模式,只是为了有些标准还用到该模式。ECB模式也不建议单独使用。 目前,本软件库的SM4针对ECB/CBC/GCM/XTS工作模式进行了绑定组合性能优化,暂时没有计划使用汇编优化HCTR模式(HCTR模式可以采用和GCM类似的方法进行汇编优化)。 **使用建议**:常用的对称加解密应用场合,推荐优先使用GCM模式,其次CBC模式(一些安全扫描工具,也会把CBC工作模式列为安全性不高的工作模式)。我能想到的GCM模式的缺点是:加解密的相关方不支持GCM模式,或者实现性能不好。 # 填充(padding) 有些分组密码算法的工作模式(譬如实现了```cipher.BlockMode```接口的模式)的输入要求是其长度必须是分组大小的整数倍。《GB/T 17964-2021 信息安全技术 分组密码算法的工作模式》附录C中列出了以下几种填充模式: * 填充方式 1,对应本软件库的```padding.NewPKCS7Padding``` * 填充方式 2,对应本软件库的```padding.NewISO9797M2Padding``` * 填充方式 3,目前没有实现,它对应ISO/IEC_9797-1 padding method 3 本软件库也实现了ANSI X9.23标准中定义的填充方式```padding.NewANSIX923Padding```,**用的最广的还是填充方式 1:PKCS7填充**。 您如果使用实现了```cipher.BlockMode```接口的分组加密工作模式,那您也必须与相关方协调好填充模式。JAVA库的对称加密算法字符串名就包含了所有信息,譬如**AES/CBC/PKCS7Padding**。 # 密文及其相关参数的传输和存储 如果是自描述的,那肯定有相关标准,定义相关ASN.1结构,并且给分组密码算法、工作模式、填充方式都赋予一个OID。 如果是内部服务之间,可能是在应用/服务级别自定义所使用分组密码算法、工作模式、填充方式的标识,作为应用的METADATA,也就是加密用的METADATA和密文分离。 也可能是隐式使用一致的分组密码算法、工作模式、填充方式,也就是代码知道,还有文档知道? 具体使用哪种方式,取决于应用场景。 另外一个就是必须和密文一起存储/传输的参数,譬如,如果使用CBC工作模式,那IV怎么办?如果是GCM模式,那Nonce、Nonce长度、Tag长度怎么办?这通常也有两种方案: * 使用预定义的ASN.1结构 * 和密文简单拼接:譬如CBC工作模式:前面16字节IV,后面ciphertext;GCM模式(使用默认Tag长度和Nonce长度):前面12字节Nonce,后面ciphertext。 至于要将二进制转为文本传输、存储,编个码就行:标准base64 / URL base64 / HEX,事先协调、定义好就可以了。 # 性能 SM4分组密码算法的软件高效实现,不算CPU指令支持的话,已知有如下几种方法: * S盒和L转换预计算 * SIMD并行处理:并行查表 * SIMD并行处理:借助CPU的AES指令,本软件库采用该方法 * SIMD并行处理:位切片(bitslicing),[参考实现](https://github.com/emmansun/sm4bs) 当然,这些与有CPU指令支持的AES算法相比,性能差距依然偏大,要是工作模式不支持并行,差距就更巨大了。 # API文档及示例 详见[API Document](https://godoc.org/github.com/emmansun/gmsm)。