专栏首页Happy的分享Golang封装ecdsa(ecc)相关工具类:密钥生成、序列化、签名、验签

Golang封装ecdsa(ecc)相关工具类:密钥生成、序列化、签名、验签

通过Go语言封装一个椭圆曲线算法(ecdsa),方便自己使用。签名算法直接写死sha256了,有需要自行修改即可。

ecc_utils.go

package ecc

import (
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"crypto/sha256"
	"crypto/x509"
	"encoding/base64"
	"encoding/hex"
	"math/big"
	"strings"
)

func GenKeyPair() (privateKey string, publicKey string, e error) {
	priKey, e := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
	if e != nil {
		return "", "", e
	}
	ecPrivateKey, e := x509.MarshalECPrivateKey(priKey)
	if e != nil {
		return "", "", e
	}
	privateKey = base64.StdEncoding.EncodeToString(ecPrivateKey)

	X := priKey.X
	Y := priKey.Y
	xStr, e := X.MarshalText()
	if e != nil {
		return "", "", e
	}
	yStr, e := Y.MarshalText()
	if e != nil {
		return "", "", e
	}
	public := string(xStr) + "+" + string(yStr)
	publicKey = base64.StdEncoding.EncodeToString([]byte(public))
	return
}

func BuildPrivateKey(privateKeyStr string) (priKey *ecdsa.PrivateKey, e error) {
	bytes, e := base64.StdEncoding.DecodeString(privateKeyStr)
	if e != nil {
		return nil, e
	}
	priKey, e = x509.ParseECPrivateKey(bytes)
	if e != nil {
		return nil, e
	}
	return
}

func BuildPublicKey(publicKeyStr string) (pubKey *ecdsa.PublicKey, e error) {
	bytes, e := base64.StdEncoding.DecodeString(publicKeyStr)
	if e != nil {
		return nil, e
	}
	split := strings.Split(string(bytes), "+")
	xStr := split[0]
	yStr := split[1]
	x := new(big.Int)
	y := new(big.Int)
	e = x.UnmarshalText([]byte(xStr))
	if e != nil {
		return nil, e
	}
	e = y.UnmarshalText([]byte(yStr))
	if e != nil {
		return nil, e
	}
	pub := ecdsa.PublicKey{Curve: elliptic.P256(), X: x, Y: y}
	pubKey = &pub
	return
}

func Sign(content string, privateKeyStr string) (signature string, e error) {
	priKey, e := BuildPrivateKey(privateKeyStr)
	if e != nil {
		return "", e
	}
	r, s, e := ecdsa.Sign(rand.Reader, priKey, []byte(hash(content)))
	if e != nil {
		return "", e
	}
	rt, e := r.MarshalText()
	st, e := s.MarshalText()
	signStr := string(rt) + "+" + string(st)
	signature = hex.EncodeToString([]byte(signStr))
	return
}

func VerifySign(content string, signature string, publicKeyStr string) bool {
	decodeSign, e := hex.DecodeString(signature)
	if e != nil {
		return false
	}
	split := strings.Split(string(decodeSign), "+")
	rStr := split[0]
	sStr := split[1]
	rr := new(big.Int)
	ss := new(big.Int)
	e = rr.UnmarshalText([]byte(rStr))
	e = ss.UnmarshalText([]byte(sStr))
	pubKey, e := BuildPublicKey(publicKeyStr)
	if e != nil {
		return false
	}
	return ecdsa.Verify(pubKey, []byte(hash(content)), rr, ss)
}

// Hash算法,这里是sha256,可以根据需要自定义
func hash(data string) string {
	sum := sha256.Sum256([]byte(data))
	return base64.StdEncoding.EncodeToString(sum[:])
}
复制代码

ecc_utils_test.go

package ecc

import "testing"

const pubKey = "MTEzODUyMzM5MzU4ODk1MzEzNzg3MzY2NzYwODUwMjE2MjQzNTE0OTc0NjkzMzM2NzA4OTYzNDY0MDk1MTUxMDkyMjY5MjM0NjE3NjMyKzc5NzY5NDM5NTI4NjcxMzc4OTQ3ODYyMzY0MjQ1ODg4ODA0MTEyMDgwOTM4MjgyNjI0MTY4NDUwNjE0NTg4MDc3MDk0MTUxNzk4NzM3"
const priKey = "MHcCAQEEIBC7/AKbbIHyVF4XJQmvqwrJMX8c8dU2JP6NcReYDlJ1oAoGCCqGSM49AwEHoUQDQgAE+7Yj9jOgDCRccssUMp1NVJExBrJCv6H8LsYUqS8lfSCwW+cdXcnmNDHM5Z2K05bJywyDIWU3f+53z0HK0I4/0Q=="
const content = "Happyjava not only java"
const signature = "36393733373630313538383036323831323937313232353733313837333336373132363935303734303237373233373433363139373530313438383239303532303635383433333733313336362b35363137383339343939383534303631323730373630343438313135333633383339333535303836313830343737333331383935333532383537333730363035313839383939353330363939"

func TestGenKeyPair(t *testing.T) {
	privateKey, publicKey, e := GenKeyPair()
	if e != nil {
		t.Error(e)
		return
	}
	t.Log("pubKey:", publicKey)
	t.Log("priKey:", privateKey)
}

func TestBuildPublicKey(t *testing.T) {
	publicKey, e := BuildPublicKey(pubKey)
	if e != nil {
		t.Error(e)
		return
	}
	t.Log("publicKey:", publicKey)
}

func TestBuildPrivateKey(t *testing.T) {
	privateKey, e := BuildPrivateKey(priKey)
	if e != nil {
		t.Error(e)
		return
	}
	t.Log("privateKey:", privateKey)
}

func TestSign(t *testing.T) {
	signature, e := Sign(content, priKey)
	if e != nil {
		t.Error(e)
	} else {
		t.Log("signature:", signature)
	}
}

func TestVerifySign(t *testing.T) {
	verify := VerifySign(content, signature, pubKey)
	t.Log("verify:", verify)
}

复制代码

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Java基于redis实现分布式锁(SpringBoot)

    分布式锁,其实原理是就是多台机器,去争抢一个资源,谁争抢成功,那么谁就持有了这把锁,然后去执行后续的业务逻辑,执行完毕后,把锁释放掉。

    Happyjava
  • beego解决跨域问题

    Happyjava
  • 【快学springboot】6.WebMvcConfigurer配置静态资源和解决跨域

    有个朋友说:为什么我配置了WebMvcConfigurer,静态资源static依然能访问?!

    Happyjava
  • 身份证校验工具类IdcardUtils

    凯哥Java
  • golang 如何验证struct字段的数据格式

    假设我们有如下结构体: type User struct { Id int Name string Bio str...

    李海彬
  • LeetCode 240. Search a 2D Matrix II

    ShenduCC
  • php前后台设计常用函数类

    V站CEO-西顾
  • 1053 住房空置率 (20 分)

    可爱见见
  • 剑指 offer -JavaScript 版(第3期23-32题)

    21.输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺...

    前端迷
  • LeetCode 8. 字符串转换整数 (atoi)

    首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。接下来的转化规则如下:

    freesan44

扫码关注云+社区

领取腾讯云代金券