Skip to content

SM2加解密性能

Sun Yimin edited this page May 23, 2024 · 12 revisions

SM2加密性能分析

image

按SM2加密算法流程来看,

  • 第1、2、3、4步属于SM2椭圆曲线计算;
  • 第5步是KDF操作,其主要也是SM3哈希计算;
  • 第6步是异或操作;
  • 第7步是SM3哈希计算;

SM2加密的性能主要是由上述7步计算共同决定的,关于SM2椭圆曲线计算,和待加密数据无关,这里可以看作常量,不作讨论。第6步异或操作,相对最简单、耗时也最少。第7步SM3哈希计算,其耗时随待加密数据长度增加而增加。我们来看看性能数据:

SM2加密(明文长度不超过32字节,使第5-7步影响最小)

goos: windows
goarch: amd64
pkg: github.com/emmansun/gmsm/sm2
cpu: Intel(R) Core(TM) i5-9500 CPU @ 3.00GHz
BenchmarkLessThan32_SM2
BenchmarkLessThan32_SM2-6
   17731	     67668 ns/op	     712 B/op	      12 allocs/op

第5步KDF

goos: windows
goarch: amd64
pkg: github.com/emmansun/gmsm/sm3
cpu: Intel(R) Core(TM) i5-9500 CPU @ 3.00GHz
BenchmarkKdfWithSM3
BenchmarkKdfWithSM3/zLen=32-kLen=32
BenchmarkKdfWithSM3/zLen=32-kLen=32-6
 5110834	       232.9 ns/op	      32 B/op	       1 allocs/op
BenchmarkKdfWithSM3/zLen=32-kLen=64
BenchmarkKdfWithSM3/zLen=32-kLen=64-6
 2580963	       463.4 ns/op	      96 B/op	       2 allocs/op
BenchmarkKdfWithSM3/zLen=32-kLen=128
BenchmarkKdfWithSM3/zLen=32-kLen=128-6
 1305332	       897.0 ns/op	     224 B/op	       3 allocs/op
BenchmarkKdfWithSM3/zLen=64-kLen=32
BenchmarkKdfWithSM3/zLen=64-kLen=32-6
 2992752	       399.6 ns/op	      32 B/op	       1 allocs/op
BenchmarkKdfWithSM3/zLen=64-kLen=64
BenchmarkKdfWithSM3/zLen=64-kLen=64-6
 1893337	       638.8 ns/op	      96 B/op	       2 allocs/op
BenchmarkKdfWithSM3/zLen=64-kLen=128
BenchmarkKdfWithSM3/zLen=64-kLen=128-6
 1000000	      1102 ns/op	     224 B/op	       3 allocs/op
BenchmarkKdfWithSM3/zLen=64-kLen=256
BenchmarkKdfWithSM3/zLen=64-kLen=256-6
  574406	      1982 ns/op	     480 B/op	       4 allocs/op
BenchmarkKdfWithSM3/zLen=64-kLen=512
BenchmarkKdfWithSM3/zLen=64-kLen=512-6
  302526	      3704 ns/op	     992 B/op	       5 allocs/op
BenchmarkKdfWithSM3/zLen=64-kLen=1024
BenchmarkKdfWithSM3/zLen=64-kLen=1024-6
  155256	      7910 ns/op	    3296 B/op	       7 allocs/op
BenchmarkKdfWithSM3/zLen=64-kLen=8192
BenchmarkKdfWithSM3/zLen=64-kLen=8192-6
   19880	     60780 ns/op	   34272 B/op	      13 allocs/op

可以看到当加密数据长度达到8K时,其耗时和完整的加密不超过32字节的耗时几乎相同

第7步SM3哈希计算

goos: windows
goarch: amd64
pkg: github.com/emmansun/gmsm/sm3
cpu: Intel(R) Core(TM) i5-9500 CPU @ 3.00GHz
BenchmarkHash1K
BenchmarkHash1K-6
  418222	      2805 ns/op	 365.01 MB/s	       0 B/op	       0 allocs/op
BenchmarkHash8K
BenchmarkHash8K-6
   57502	     20781 ns/op	 394.21 MB/s	       0 B/op	       0 allocs/op

可以看到当加密数据长度达到8K时,其耗时几乎和达到了加密不超过32字节的耗时的1/3。但是,目前SM3的软件实现的优化空间已经不大。

KDF软件实现优化分析

image

针对SM2的KDF,有以下特点:

  • 输入的比特串Z的长度固定,为64字节,正好为SM3的一个处理块长度。第二个处理块,也是尾块,由ct开头,后续由填充和长度68构成。
  • klen决定了要调用哈希运算的次数:(klen + v - 1) / v,每次哈希运算无依赖。

从上面两个特点可以看出,可以有下面优化方向:

  • 每次哈希运算的第一个块是相同的,这个可以只计算一次,然后共享,避免重复计算。这个优化比较简单,尤其是自己实现的SM3。
  • 每次哈希运算相互无依赖,可以并行计算。这个优化比较复杂,代码量大。

关于SM3基于SIMD的多路并行

目前已经有好多基于SIMD的哈希算法实现:MD5,SHA256,也包括SM3。通用SIMD多路并行设计实现的难点在于输入、输出协调处理,象SM2-KDF这种应用场景是最简单的:处理的数据块数相同,数据源单一。预测当待加密数据足够长的情况下,SM2加密性能能赶上(甚至超过?)无SM4-NI的SM4-CBC的性能。接下来会做一些实验性实现,观察一下效果。

关于密文格式C1C2C3和C1C3C2

C1C2C3更适合加密流式处理:

  • 用公钥生成Encrypter。
  • 生成随机数和点C1,随之生成Z,初始化KDF(COUNTER及HASH(Z)),输出C1点。
  • XOR Stream,输出部分密文C2;同时计算C3,也就是认证码。
  • Finalize,输出最终C3值。

解密过程:

  • 用私钥生成Decrypter。
  • 读入至少96字节,生成C1,随之生成Z,初始化KDF(COUNTER及HASH(Z))。
  • XOR Stream, 输出部分明文;同时计算C3'。这一步要特殊处理,缓冲区中至少保留后32字节。
  • Finalize,如果缓冲区数据长度超过32字节,则先对多出部分(前n字节)继续进行XOR stream动作,计算最终C3',和缓冲区中的最后32字节进行比较,相等则返回成功,否则失败。

由此可见,解密时C1C2C3比C1C3C2复杂一点,但C1C3C2做不到流式加密。当然,如果我们严格按照SM2非对称加密设计的初衷,只对少量数据进行加解密,则各种格式都没什么问题。

结论

经过KDF共享Z状态优化后:

goos: windows
goarch: amd64
pkg: github.com/emmansun/gmsm/sm2
cpu: Intel(R) Core(TM) i5-9500 CPU @ 3.00GHz
BenchmarkEncrypt1K_SM2
BenchmarkEncrypt1K_SM2-6
   15978	     74357 ns/op	  13.77 MB/s	    3880 B/op	      14 allocs/op
BenchmarkEncrypt8K_SM2
BenchmarkEncrypt8K_SM2-6
    7197	    140847 ns/op	  58.16 MB/s	   18344 B/op	      13 allocs/op   
BenchmarkSM4CBCEncrypt1K
BenchmarkSM4CBCEncrypt1K-6
  142844	      8071 ns/op	 126.88 MB/s	       0 B/op	       0 allocs/op   
BenchmarkSM4CBCEncrypt8K
BenchmarkSM4CBCEncrypt8K-6
   18459	     65322 ns/op	 125.41 MB/s	       0 B/op	       0 allocs/op  
BenchmarkSM4GCMSeal1K
BenchmarkSM4GCMSeal1K-6
  514671	      2036 ns/op	 502.89 MB/s	       0 B/op	       0 allocs/op  
BenchmarkSM4GCMSeal8K
BenchmarkSM4GCMSeal8K-6
   76536	     15293 ns/op	 535.67 MB/s	       0 B/op	       0 allocs/op

KDF AVX2 8路并行后:

goos: windows
goarch: amd64
pkg: github.com/emmansun/gmsm/sm3
cpu: Intel(R) Core(TM) i5-9500 CPU @ 3.00GHz
BenchmarkKdfWithSM3
BenchmarkKdfWithSM3/zLen=32-kLen=32
BenchmarkKdfWithSM3/zLen=32-kLen=32-6
 5110020	       229.9 ns/op	      32 B/op	       1 allocs/op
BenchmarkKdfWithSM3/zLen=32-kLen=64
BenchmarkKdfWithSM3/zLen=32-kLen=64-6
 2790901	       423.9 ns/op	      64 B/op	       1 allocs/op
BenchmarkKdfWithSM3/zLen=32-kLen=128
BenchmarkKdfWithSM3/zLen=32-kLen=128-6
 2514219	       467.8 ns/op	     128 B/op	       1 allocs/op
BenchmarkKdfWithSM3/zLen=64-kLen=32
BenchmarkKdfWithSM3/zLen=64-kLen=32-6
 3024373	       399.9 ns/op	      32 B/op	       1 allocs/op
BenchmarkKdfWithSM3/zLen=64-kLen=64
BenchmarkKdfWithSM3/zLen=64-kLen=64-6
 2027554	       596.3 ns/op	      64 B/op	       1 allocs/op
BenchmarkKdfWithSM3/zLen=64-kLen=128
BenchmarkKdfWithSM3/zLen=64-kLen=128-6
 1744693	       691.4 ns/op	     128 B/op	       1 allocs/op
BenchmarkKdfWithSM3/zLen=64-kLen=256
BenchmarkKdfWithSM3/zLen=64-kLen=256-6
 1397571	       811.7 ns/op	     256 B/op	       1 allocs/op
BenchmarkKdfWithSM3/zLen=64-kLen=512
BenchmarkKdfWithSM3/zLen=64-kLen=512-6
  862700	      1385 ns/op	     512 B/op	       1 allocs/op
BenchmarkKdfWithSM3/zLen=64-kLen=1024
BenchmarkKdfWithSM3/zLen=64-kLen=1024-6
  507590	      2364 ns/op	    1024 B/op	       1 allocs/op
BenchmarkKdfWithSM3/zLen=64-kLen=8192
BenchmarkKdfWithSM3/zLen=64-kLen=8192-6
   70632	     17524 ns/op	    8192 B/op	       1 allocs/op
goos: windows
goarch: amd64
pkg: github.com/emmansun/gmsm/sm2
cpu: Intel(R) Core(TM) i5-9500 CPU @ 3.00GHz
BenchmarkEncrypt1K_SM2
BenchmarkEncrypt1K_SM2-6
   16662	     72808 ns/op	  14.06 MB/s	    2856 B/op	      13 allocs/op
BenchmarkEncrypt8K_SM2
BenchmarkEncrypt8K_SM2-6
   10861	    111046 ns/op	  73.77 MB/s	   18344 B/op	      13 allocs/op
BenchmarkEncrypt1M_SM2
BenchmarkEncrypt1M_SM2-6
     205	   5856919 ns/op	 179.03 MB/s	 2106029 B/op	      13 allocs/op
BenchmarkSM4CBCEncrypt1M
BenchmarkSM4CBCEncrypt1M-6
     100	  10017195 ns/op	 104.68 MB/s	   10489 B/op	       0 allocs/op

当待加密数据足够长时,SM2加密性能比SM4-CBC要好,只是多用一些内存。