内容简介:近期go项目对接第三方Java服务,第三方要求使用国密sm3/sm2算法进行数据签名验签,特记录go端开发注意事项密钥生成可以使用openssl库,openssl版本至少是1.1.1,终端运行检查椭圆曲线是否包含sm2,如下所示是支持sm2的。
近期 go 项目对接第三方 Java 服务,第三方要求使用国密sm3/sm2算法进行数据签名验签,特记录go端开发注意事项
1 关于密钥对
密钥生成可以使用openssl库,openssl版本至少是1.1.1,终端运行 openssl version
检查版本,之前版本不支持sm2/sm3, openssl官网 https://www.openssl.org/source/
检查椭圆曲线是否包含sm2,如下所示是支持sm2的。
$ openssl ecparam -list_curves | grep SM2 SM2 : SM2 curve over a 256 bit prime field
密钥生成流程,存在第四步的原因是go使用的库需要读取pkcs#8格式私钥pem文件:
1 生成sm2私钥: openssl ecparam -genkey -name SM2 -out sm2PriKey.pem
2 sm2私钥导出公钥: openssl ec -in sm2PriKey.pem -pubout -out sm2PubKey.pem
3 查看私钥: openssl ec -in sm2PriKey.pem -text
4 私钥pkcs#1转pkcs#8: openssl pkcs8 -topk8 -inform PEM -in sm2PriKey.pem -outform pem -nocrypt -out sm2PriKeyPkcs8.pem
2 go签名验签代码
1 读取公钥pem文件, 将公钥X/Y的bytes拼接base64编码,函数示例:
func DealPubKey() {
// 公钥X/Y的bytes拼接后base64编码
PubKeyPath := "/home/xx/sm2PubKey.pem"
pubKey, e := sm2.ReadPublicKeyFromPem(PubKeyPath, nil)
if e != nil {
log.Println("pubKeyPem read failed, error: ", e)
}
var buf bytes.Buffer
buf.Write(pubKey.X.Bytes())
buf.Write(pubKey.Y.Bytes())
XY := base64.StdEncoding.EncodeToString(buf.Bytes())
log.Println("pubKey XY base64--->", XY)
}
2 sm2签名验签使用的包"github.com/tjfoc/gmsm/sm2", go mod自动安装不会安装最新版本, go.mod不要添加此包,
github最新版本是是V1.2, 切换到项目目录, 终端运行 go get github.com/tjfoc/gmsm@master
安装最新版本后会自动添加到go.mod
3 "github.com/tjfoc/gmsm/sm2"使用签名函数为 sm2.Sm2Sign, 此函数会将输入的[]bytes类型数据sm3摘要运算后进行sm2签名, 对应验签函数sm2.Sm2Verify
4 函数sm2.Sign默认是使用sha-512进行摘要运算,与服务端Java签名验签失败.
代码示例:
package main
import (
"bytes"
"encoding/base64"
"fmt"
"github.com/tjfoc/gmsm/sm2"
"github.com/tjfoc/gmsm/sm3"
"log"
"math/big"
"os"
)
var (
default_uid = []byte{0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38}
)
func Sign(body string) (string, error) {
cwd, _ := os.Getwd()
PriKeyPath := cwd + string(os.PathSeparator) + "sm2PriKeyPkcs8.pem"
priKey, e := sm2.ReadPrivateKeyFromPem(PriKeyPath, nil)
if e != nil {
log.Println("priKeyPem read failed, error: ", e)
return "", e
}
r, s, err := sm2.Sm2Sign(priKey, []byte(body), default_uid)
if err != nil {
log.Println("priKey sign error: ", err)
return "", err
}
//Buffer是一个实现了读写方法的可变大小的字节缓冲
var buffer bytes.Buffer
buffer.Write(r.Bytes())
buffer.Write(s.Bytes())
signature := base64.StdEncoding.EncodeToString(buffer.Bytes())
log.Println("priKey signature base64: ", signature)
return signature, nil
}
func Verify(body, signature string) {
cwd, _ := os.Getwd()
PubKeyPath := cwd + string(os.PathSeparator) + "sm2PubKey.pem"
pubKey, e := sm2.ReadPublicKeyFromPem(PubKeyPath, nil)
if e != nil {
log.Println("pubKeyPem read failed, error: ", e)
}
d64, err := base64.StdEncoding.DecodeString(signature)
if err != nil {
log.Println("base64 decode error: ", err)
}
l := len(d64)
br := d64[:l/2]
bs := d64[l/2:]
var ri, si big.Int
r := ri.SetBytes(br)
s := si.SetBytes(bs)
v := sm2.Sm2Verify(pubKey, []byte(body), default_uid, r, s)
log.Printf("pubKey verified: %v\n", v)
}
func main() {
body := `{"name":"mike","gender":"male"}`
signature, _ := Sign(body)
Verify(body, signature)
}
以上所述就是小编给大家介绍的《go/Java 国密sm2签名验签》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 用 Python 制作一个艺术签名小工具,给自己设计一个优雅的签名
- 强随机数应用链链RandDrop已上线——BLS签名实现阈值签名的流程
- Android应用签名打包
- [原]数字签名
- iOS 签名机制
- 封装Apk签名工具
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Head First Design Patterns
Elisabeth Freeman、Eric Freeman、Bert Bates、Kathy Sierra、Elisabeth Robson / O'Reilly Media / 2004-11-1 / USD 49.99
You're not alone. At any given moment, somewhere in the world someone struggles with the same software design problems you have. You know you don't want to reinvent the wheel (or worse, a flat tire),......一起来看看 《Head First Design Patterns》 这本书的介绍吧!