golang使用SM2(SM2withSM3)签名、验签数据

场景

对接招行支付

标准

密钥

私钥:Hex格式,SM2标准秘钥格式,私钥为32字节字节流,转换为HEX格式为64字节
公钥:base64格式,并且符合ANS1标准,base64编码后总长度为124字节
SM2标准公钥头:3059301306072A8648CE3D020106082A811CCF5501822D03420004

签名算法

数字签名采用SM2withSM3签名算法,签名方式为PKCS#1裸签名,签名USER_ID使用国密局推荐ID,即“1234567812345678”,使用国密私钥对签名字符串进行加签,生成签名值。

Start

依赖

import (
	"crypto/rand"
	"encoding/base64"
	"encoding/hex"
	"fmt"
	"github.com/ZZMarquis/gm/sm2"
	"strings"
)

公钥转base64

func PubToBase64(pub *sm2.PublicKey) string {
	pub.GetRawBytes()
	bytes := pub.X.Bytes()
	bytes = append(bytes, pub.Y.Bytes()...)
	pubHex := "3059301306072a8648ce3d020106082a811ccf5501822d03420004" + hex.EncodeToString(bytes)
	decode, _ := hex.DecodeString(pubHex)
	base64Pub := base64.StdEncoding.EncodeToString(decode)
	return base64Pub
}

私钥转hex

func PriToHex(pri *sm2.PrivateKey) string {
	hex := hex.EncodeToString(pri.GetRawBytes())
	return hex
}

私钥生成公钥

func PriToBase64Pub(pri *sm2.PrivateKey) string {
	pub := sm2.CalculatePubKey(pri)
	base64Pub := PubToBase64(pub)
	return base64Pub
}

生成密钥对

func Generate() (string, string) {
	pri, pub, _ := sm2.GenerateKey(rand.Reader)
	return PriToHex(pri), PubToBase64(pub)
}

Hex私钥转私钥对象

func HexToPri(priStr string) *sm2.PrivateKey {
	// 解码hex私钥
	privateKeyByte, _ := hex.DecodeString(priStr)
	// 转成go版的私钥
	pri, err := sm2.RawBytesToPrivateKey(privateKeyByte)
	if err != nil {
		panic("私钥加载异常")
	}
	return pri
}

base64公钥转公钥对象

func Base64ToPub(pubStr string) *sm2.PublicKey {
	decode, _ := base64.StdEncoding.DecodeString(pubStr)
	pubHex := hex.EncodeToString(decode)
	pubHex = strings.ReplaceAll(pubHex, "3059301306072a8648ce3d020106082a811ccf5501822d03420004", "")
	pubByte, _ := hex.DecodeString(pubHex)
	pub, _ := sm2.RawBytesToPublicKey(pubByte)
	return pub
}

签名

func Sign(data string, pri *sm2.PrivateKey) string {
	signature, err := sm2.Sign(pri, []byte("1234567812345678"), []byte(data))
	if err != nil {
		panic("云闪付签名错误")
	}
	// 转 base64
	sign := base64.StdEncoding.EncodeToString(signature)
	return sign
}

验签

func Verify(data, sign string, pub *sm2.PublicKey) bool {
	sign1, _ := base64.StdEncoding.DecodeString(sign)
	return sm2.Verify(pub, []byte("1234567812345678"), []byte(data), sign1)
}

测试

func Test() {
	//生成密钥对
	hexPri, basePub := Generate()
	println("******* 生成 hex私钥:" + hexPri)
	println("******* 生成 base公钥:" + basePub)
	//Hex私钥转私钥对象
	pri := HexToPri(hexPri)
	//base64公钥转公钥对象
	pub := Base64ToPub(basePub)
	//私钥生成公钥
	base64Pub := PriToBase64Pub(pri)
	println("******* 私钥生成base64公钥:" + base64Pub)
	//私钥转hex
	priHex := PriToHex(pri)
	println("******* 私钥转hex:" + priHex)
	//公钥转base64
	pubBase := PubToBase64(pub)
	println("******* 公钥转base64:" + pubBase)
	//签名
	sign := Sign("abc=123", pri)
	println("******* 签名:" + sign)
	//验签
	ver := Verify("abc=123", sign, pub)
	println(fmt.Sprintf("******* 验签:%t", ver))
}
******* 生成 hex私钥:ad606a552feb3b46b2ad47eab8491da7a97d796385b01149aac1e3e5c53f876a
******* 生成 base公钥:MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEJhdEFCw7pKnAR9mPZYKCkntiz+A1HRX5rDP1a2lYQjxXY2zLm4PoYm9hdlayBkGx/kzr/EIeapsxJa5Y+fAxMg==
******* 私钥生成base64公钥:MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEJhdEFCw7pKnAR9mPZYKCkntiz+A1HRX5rDP1a2lYQjxXY2zLm4PoYm9hdlayBkGx/kzr/EIeapsxJa5Y+fAxMg==
******* 私钥转hex:ad606a552feb3b46b2ad47eab8491da7a97d796385b01149aac1e3e5c53f876a
******* 公钥转base64:MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEJhdEFCw7pKnAR9mPZYKCkntiz+A1HRX5rDP1a2lYQjxXY2zLm4PoYm9hdlayBkGx/kzr/EIeapsxJa5Y+fAxMg==
******* 签名:MEQCIEn0F0EUVWGNvH7bMiveXNHFzOCVZkT+X4Y9zI9AL/HLAiAMScSwJs/8ZEf2QLw4ThYYqWvgAG+A0Lj3bq+ljvww6Q==
******* 验签:true

以下是使用golang进行SM2签名和验证的示例代码: ```go package main import ( "crypto/rand" "crypto/sm2" "crypto/x509" "encoding/asn1" "encoding/base64" "encoding/hex" "fmt" ) func main() { // 生成SM2密钥对 privateKey, err := sm2.GenerateKey() if err != nil { panic(err) } publicKey := &privateKey.PublicKey // 待签名数据 data := []byte("hello world") // 签名 r, s, err := sm2.Sign(rand.Reader, privateKey, data) if err != nil { panic(err) } // 将签名结果转换为DER编码 signature, err := asn1.Marshal(sm2Signature{r, s}) if err != nil { panic(err) } // 验证签名 ok := sm2.Verify(publicKey, data, r, s) fmt.Println("Verify result:", ok) // 将公钥转换为PEM格式 publicKeyBytes, err := x509.MarshalPKIXPublicKey(publicKey) if err != nil { panic(err) } publicKeyPEM := pemEncode("PUBLIC KEY", publicKeyBytes) // 将私钥转换为PEM格式 privateKeyBytes, err := x509.MarshalECPrivateKey(privateKey) if err != nil { panic(err) } privateKeyPEM := pemEncode("EC PRIVATE KEY", privateKeyBytes) fmt.Println("Public key (PEM):") fmt.Println(publicKeyPEM) fmt.Println("Private key (PEM):") fmt.Println(privateKeyPEM) fmt.Println("Signature (DER):") fmt.Println(hex.EncodeToString(signature)) } // 将DER编码的数据转换为SM2签名结构体 type sm2Signature struct { R, S *big.Int } // 将数据编码为PEM格式 func pemEncode(blockType string, data []byte) string { pemData := &pem.Block{ Type: blockType, Bytes: data, } return base64.StdEncoding.EncodeToString(pem.EncodeToMemory(pemData)) } ``` 上述代码中,我们首先生成了一个SM2密钥对,然后使用私钥对数据进行签名,并将签名结果转换为DER编码。接着,我们使用公钥对签名进行验证,验证结果为true。最后,我们将公钥和私钥转换为PEM格式,并将签名结果以16进制字符串的形式输出。
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bug的搬运工

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值