0
SM2加解密性能
Sun Yimin edited this page 2024-05-23 21:21:25 +08:00
This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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的哈希算法实现MD5SHA256也包括SM3。通用SIMD多路并行设计实现的难点在于输入、输出协调处理SM2-KDF这种应用场景是最简单的处理的数据块数相同数据源单一。预测当待加密数据足够长的情况下SM2加密性能能赶上甚至超过无SM4-NI的SM4-CBC的性能。接下来会做一些实验性实现观察一下效果。

关于密文格式C1C2C3和C1C3C2

C1C2C3更适合加密流式处理

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

解密过程:

  • 用私钥生成Decrypter。
  • 读入至少96字节生成C1随之生成Z初始化KDFCOUNTER及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要好只是多用一些内存。