SM2加密算法

SM2算法是一种基于椭圆曲线密码的公钥密码算法,其安全性主要基于椭圆曲线离散对数难题。该算法由国家密码管理局设计并公开,是我国自主创新的一种密码算法,可应用于数据加密、解密、数字签名等操作。SM2算法包括密钥生成算法、加密算法、解密算法和数字签名算法等部分。

SM2加密算法过程如下:

用户A的原始数据为椭圆曲线系统参数、长度为klen比特的消息M、公钥PB

  1. 产生随机数k∈[1,n-1]

  2. 计算椭圆曲线点C1=[k]G=(x1,y1)

  3. 计算椭圆曲线点S=[h]PB

  4. 计算[k]PB=(x2,y2)

  5. 计算t=KDF(x2||y2,klen)

  6. 计算C2=M⊕t

  7. 计算C3=Hash(x2||M||y2)

  8. 输出密文C=C1||C2||C3

image-20241201151129640

其中椭圆曲线方程为

img

密钥派生函数KDF

KDF密钥派生函数在标准GB/T 32918.4 《信息安全技术 SM2椭圆曲线公钥密码算法 第4部分:公钥加密算法》中定义,本质上是进行哈希运算扩展长度,再截取相应长度字段,如下所示:

image-20241201151216812

使用Python代码实现SM2中的KDF函数如下:

from math import ceil
from gmssl.sm3 import sm3_hash

Z="57E7B63623FAE5F08CDA468E872A20AFA03DED41BF1403770E040DC83AF31A67991F2B01EBF9EFD8881F0A0493000603"


def hex2byte(msg): 
  ml = len(msg)
  if ml % 2 != 0:
    msg = '0'+ msg
  ml = int(len(msg)/2)
  msg_byte = []
  for i in range(ml):
    # print(msg[i*2:i*2+2])
    msg_byte.append(int(msg[i*2:i*2+2],16))
  return msg_byte

def KDF(Z,klen): 
  klen = int(klen)
  ct = 0x00000001
  rcnt = ceil(klen/32)
  Zin = hex2byte(Z)
  Ha = ""
  for i in range(rcnt):
    msg = Zin  + hex2byte('%08x'% ct)
    # print(msg)
    Ha = Ha + sm3_hash(msg)
    # print(Ha)
    ct += 1
  return Ha[0: klen * 2]

print(KDF(Z,19).upper())

其实KDF就是一个使用SM3算法不断拓展长度的过程,对上述脚本进行分析

  1. hex2byte 函数:
    • 目的: 将 16 进制字符串转换为字节数组。
    • 流程:
      • 检查输入字符串的长度是否为偶数。如果不是,前面补零以确保每两个字符组成一个字节。
      • 将字符串的每两个字符作为 16 进制数解析成一个字节,并将其加入字节数组。
  2. KDF 函数:
    • 目的: 从输入数据 Z 派生出指定长度 klen 的密钥。
    • 参数:
      • Z: 16 进制表示的比特串。
      • klen: 希望生成的密钥长度(以字节为单位)。
    • 流程:
      • ct 初始化为 1,表示计数器。
      • 计算需要多少次哈希运算,即 rcnt = ceil(klen / 32)
      • Z 转换为字节数组。
      • 循环 rcnt 次,每次将 Z 和当前 ct 组合,计算其 SM3 哈希值,并将结果累积到 Ha 中。
      • ct 在每次循环之后递增。
      • 最终,返回派生出的密钥(Ha 的前 klen * 2 个十六进制字符)。
  3. SM3 哈希:
    • 使用 sm3_hash 函数进行哈希计算,该函数来自 gmssl 库的实现。