当前位置: 首页 > 工具软件 > gmssl-python > 使用案例 >

关于Python的GMSSL库里面验证签名无法与别的工具通用的问题

许阿苏
2023-12-01

  由于工作原因,需要使用到国密加密算法,而且需要使用Python来做,于是就找来了Python中的gmssl库函数来进行使用。

  在使用gmssl库的时候,可以使用在这个函数当中进行上面sm2自我签名与验签,但是其他工具产生的sm2签名无法通过该工具进行签名验证。在查找了GitHub之后,发现了问题所在,在对于sm2签名的时候,该函数是直接对于源数据进行签名,在算法的标准当中,签名是需要进行hash算法,对于源数据进行hash计算,产生中间值e,签名是对e进行签名的,同样,验签也是对e进行验签,所以该函数是不正确的。

  改进办法,采用函数,对于原始数据进行hash计算,得出e值之后,使用e值进行签名与验签,即可和其他工具进行通用。

  首先对于用户输入的参数进行计算Za值,使用sm3算法,算法的过程如下:

def sm2_hash_e(data, id, idlen, publickey):   
    a = b'\xFF\xFF\xFF\xFE\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF' \
        b'\xFF\xFF\xFF\xFF\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFC'

    b = b'\x28\xE9\xFA\x9E\x9D\x9F\x5E\x34\x4D\x5A\x9E\x4B\xCF\x65\x09\xA7' \
        b'\xF3\x97\x89\xF5\x15\xAB\x8F\x92\xDD\xBC\xBD\x41\x4D\x94\x0E\x93'

    gx = b'\x32\xc4\xae\x2c\x1f\x19\x81\x19\x5f\x99\x04\x46\x6a\x39\xc9\x94' \
         b'\x8f\xe3\x0b\xbf\xf2\x66\x0b\xe1\x71\x5a\x45\x89\x33\x4c\x74\xc7'

    gy = b'\xbc\x37\x36\xa2\xf4\xf6\x77\x9c\x59\xbd\xce\xe3\x6b\x69\x21\x53' \
         b'\xd0\xa9\x87\x7c\xc6\x2a\x47\x40\x02\xdf\x32\xe5\x21\x39\xf0\xa0'
    pubkey_xtemp = publickey[0:64]
    pubkey_ytemp = publickey[64:128]

    pubkey_x = str2bytes(pubkey_xtemp, 64)
    pubkey_y = str2bytes(pubkey_ytemp, 64)

    if idlen == 0:
        entl = b'\x00\x00'
        
        Zatemp = entl + a + b + gx + gy + pubkey_x + pubkey_y
    else:
        lentemp = 4 * idlen
        entl = int.to_bytes(lentemp, 2, byteorder='big', signed=False)
        idtemp = str2bytes(id, idlen)
        Zatemp = entl + idtemp + a + b + gx + gy + pubkey_x + pubkey_y
  
    Zatemp_v2 = byte2hex(Zatemp)

  在此之后对于Za值与原始数据进行结合,计算出可以使用的e值

 etemp = Za + data
 e = Hash_sm3(etemp, 1)
 resbytes = str2bytes(e, 64)

此时的e值可以作为Python中gmssl库中的验签函数的原始数据输入,可以和别的工具相互验证

对于验证的sm2值,需要考虑到的还有是否需要使用userID,在使用userID的时候,对于za值的计算是有一些区别的,在处理的时候,封装成为一个接口函数,此时由于使用的原因,我接收的参数都是十六进制的bytes值,所以我封装成了对于bytes验证的函数:

    def SM2_sign_verify(originaldata, publickey, signvalue, id=''):
        pubkey = publickey.hex()
        origin = originaldata.hex()
        sign = signvalue.hex()
        sm2_crypt = sm2.CryptSM2(
            public_key=pubkey, private_key='')
        idlen = len(id)
        if idlen == 0:
            e = sm2_hash_e(origin, 0, 0, pubkey)
        else:
            e = sm2_hash_e(origin, id, idlen, pubkey)
        try:
            assert sm2_crypt.verify(sign, e)
            return 1
        except:
            return 0

  这一部分的代码可以根据具体的需求进行更改,参数一是原始数据,参数二是公钥,参数三是签名值,参数四是userID(可以为空),有需求的话可以根据情况在函数开始处转换数据格式。

  该函数验证成功返回1,失败则返回0。

  具体实现部分打包成文件上传,配合上面的函数接口与gmssl库进行使用,即可实现与别的签名工具互通签名与签名验证。

 类似资料: