现在国密算法用的是越来越多,之前JAVA采用hutool工具包进行签名,还算顺利,但是最近想把功能切到python中,困扰了我大半年时间,终于得到解决。
其实官方的例子没有问题,如下:
1. 初始化CryptSM2
import base64 import binascii from gmssl import sm2, func #16进制的公钥和私钥 private_key = '00B9AB0B828FF68872F21A837FC303668428DEA11DCD1B24429D0C99E24EED83D5' public_key = 'B9C9A6E04E9C91F7BA880429273747D7EF5DDEB0BB2FF6317EB00BEF331A83081A6994B8993F3F5D6EADDDB81872266C87C018FB4162F5AF347B483E24620207' sm2_crypt = sm2.CryptSM2( public_key=public_key, private_key=private_key)
2. sign_with_sm3
data = b"111" # bytes类型 sign = sm2_crypt.sign_with_sm3(data) # 16进制
问题:
1、之前做Java的时候,签名只需要设置私钥,公钥设置为空,所以我使用gmssl进行签名,也想当然的把公钥设置''(其实gmssl不允许public_key设置为None,就应该想到),导致签名的值一直无法验签。所以再次强调,gmssl签名一定要设置公钥
2、gmssl获取公钥时,有个小bug
self.public_key = public_key.lstrip("04") if public_key.startswith("04") else public_key
如果公钥类似于0449A6E04E9C91F7BA880429273747D7EF5DDEB0BB2FF6317EB00BEF331A83081A6994B8993F3F5D6EADDDB81872266C87C018FB4162F5AF347B483E24620207,那么会把前面的044都给去掉了,所以如果公钥时04开头的话,就自己写代码把04去掉。
同时参数需要注意一下:
1、mode
我看源码中写的注释为:mode: 0-C1C2C3, 1-C1C3C2 (default is 1)
好像错了,实际上应该是0-C1C3C2,默认也是0
Java中的设置为sm2.setMode(SM2Engine.Mode.C1C3C2);
2、asn1
asn1=False是明文形式
Java的设置为sm2.usePlainEncoding()
把自己趟过的坑记录下来,同时也希望能对使用国密的开发人员有所帮助。