go/Java 国密sm2签名验签

栏目: Java · 发布时间: 6年前

内容简介:近期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签名验签》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

暗趋势

暗趋势

王煜全 / 中信出版集团 / 2019-1 / 59元

《暗趋势》由得到“全球创新260讲”专栏主讲人王煜全,为你揭示藏在科技浪潮中的商业机会,教你获得把握趋势的能力,发现小趋势,抓住大机遇。 《暗趋势》聚焦于改变你生活和未来的产业,深度解读人工智能、混合现实、区块链、生物医疗等你必须关注的科技行业,并分析新科技给企业和个人带来的发展机遇,前瞻性提出企业和个人的思维与行动应对策略。 王煜全作为全球科技前哨侦察兵,以其每年5亿元的科技投资及2......一起来看看 《暗趋势》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

MD5 加密
MD5 加密

MD5 加密工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具