-
Notifications
You must be signed in to change notification settings - Fork 67
SM2加解密性能
Sun Yimin edited this page May 23, 2024
·
12 revisions
按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的软件实现的优化空间已经不大。
针对SM2的KDF,有以下特点:
- 输入的比特串Z的长度固定,为64字节,正好为SM3的一个处理块长度。第二个处理块,也是尾块,由ct开头,后续由填充和长度68构成。
- klen决定了要调用哈希运算的次数:(klen + v - 1) / v,每次哈希运算无依赖。
从上面两个特点可以看出,可以有下面优化方向:
- 每次哈希运算的第一个块是相同的,这个可以只计算一次,然后共享,避免重复计算。这个优化比较简单,尤其是自己实现的SM3。
- 每次哈希运算相互无依赖,可以并行计算。这个优化比较复杂,代码量大。
目前已经有好多基于SIMD的哈希算法实现:MD5,SHA256,也包括SM3。通用SIMD多路并行设计实现的难点在于输入、输出协调处理,象SM2-KDF这种应用场景是最简单的:处理的数据块数相同,数据源单一。预测当待加密数据足够长的情况下,SM2加密性能能赶上(甚至超过?)无SM4-NI的SM4-CBC的性能。接下来会做一些实验性实现,观察一下效果。
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要好,只是多用一些内存。