Go 实现:椭圆曲线数字签名算法ECDSA

一、ECDSA概述

     椭圆曲线数字签名算法(ECDSA)是使用椭圆曲线密码(ECC)对数字签名算法(DSA)的模拟。它基于椭圆曲线离散对数问题(ECDLP)的难解性,具有密钥短、速度快和安全性高的优点。与传统的离散对数问题(DLP)和大数分解问题(IFP)不同,椭圆曲线离散对数问题没有亚指数时间的解决方法,因此椭圆曲线密码的安全性更高。

二、ECDSA工作原理

ECDSA的签名过程包括以下步骤:

  1. 选择一条椭圆曲线Ep(a,b)和基点G;
  2. 选择私有密钥k(k<n,n为G的阶),利用基点G计算公开密钥K=kG;
  3. 产生一个随机整数r(r<n),计算点R=rG;
  4. 将原数据和点R的坐标值x,y作为参数,计算SHA1做为hash,即Hash=SHA1(原数据,x,y);
  5. 计算s≡r−Hash∗k(modn);
  6. r和s做为签名值,如果r和s其中一个为0,重新从第3步开始执行。

验证过程如下:

  1. 接受方在收到消息m和签名值r,s后,进行以下运算;
  2. 计算sG+H(m)P=(x1,y1),r1≡x1modp;
  3. 验证等式:r1≡rmodp;
  4. 如果等式成立,接受签名,否则签名无效。

三、Go实现

1. 生成私钥和公钥,生成的私钥为结构体ecdsa.PrivateKey的指针

func NewKeyPair()(ecdsa.PrivateKey,[]byte){
	//生成secp256椭圆曲线
	curve := elliptic.P256()
	//产生的是一个结构体指针,结构体类型为ecdsa.PrivateKey
	private,err := ecdsa.GenerateKey(curve, rand.Reader)
	if err != nil{
		log.Panic(err)
	}

	
	fmt.Printf("私钥:%x\n", private)
	fmt.Printf("私钥X:%x\n", private.X.Bytes())
	fmt.Printf("私钥Y:%x\n", private.Y.Bytes())
	fmt.Printf("私钥D:%x\n", private.D.Bytes())

	//x坐标与y坐标拼接在一起生成公钥
	pubKey := append(private.X.Bytes(),private.Y.Bytes()...)
	//打印公钥,公钥用16进制打印出来长度为128,包含了x轴坐标与y轴坐标。
	fmt.Printf("公钥:%x \n", pubKey)

	return *private, pubKey
}

2.生成签名的DER格式

func MakeSignatureDerString(r,s string)string{
	//获取R和S的长度
	lenSigR := len(r)/2
	lenSigS := len(s)/2

	//计算DER序列的总长度
	lenSequence := lenSigR + lenSigS + 4

	//将10进制长度转16进制字符串
	strLenSigR := DecimalToHex(int64(lenSigR))
	strLenSigS := DecimalToHex(int64(lenSigS))
	strLenSequence := DecimalToHex(int64(lenSequence))

	// 拼凑DER编码
	derString := "30" + strLenSequence
	derString = derString + "02" + strLenSigR + r
	derString = derString + "02" + strLenSigS + s
	derString = derString + "01"

	return derString
}

3.验证签名1

func VerifySignature1(pubKey,message []byte, r,s *big.Int)bool{
	curve := elliptic.P256()

	//公钥的长度
	keyLen := len(pubKey)

	//前一半为x轴坐标,后一半为y轴坐标
	x := big.Int{}
	y := big.Int{}
	x.SetBytes(pubKey[:(keyLen / 2)])
	y.SetBytes(pubKey[:(keyLen / 2)])
	rawPubKey := ecdsa.PublicKey{curve,&x,&y}

	//根据交易哈希、公钥、数字签名验证成功。ecdsa.Verify func Verify(pub *PublicKey,
	//hash []byte, r *big.Int, s *big.Int) bool
	res := ecdsa.Verify(&rawPubKey, message, r, s)

	return res	
}

4.验证签名2

func VerifySignature2(pubKey, message []byte, r, s string) bool {
	curve := elliptic.P256()

	//公钥的长度
	keyLen := len(pubKey)

	//前一半为x轴坐标,后一半为y轴坐标
	x := big.Int{}
	y := big.Int{}
	x.SetBytes(pubKey[:(keyLen / 2)])
	y.SetBytes(pubKey[(keyLen / 2):])
	rawPubKey := ecdsa.PublicKey{curve, &x, &y}
	
	//根据交易哈希、公钥、数字签名验证成功。ecdsa.Verify func Verify(pub *PublicKey,
	//hash []byte, r *big.Int, s *big.Int) bool
	rint := big.Int{}
	sint := big.Int{}
	rByte, _ := hex.DecodeString(r)
	sByte, _ := hex.DecodeString(s)
	rint.SetBytes(rByte)
	sint.SetBytes(sByte)
	
	//fmt.Println("------", rint.SetBytes(rByte))
	//fmt.Println("------", sint.SetBytes(sByte))
	res := ecdsa.Verify(&rawPubKey, message, &rint, &sint)

	return res
}

func DecimalToHex(n int64) string {

	if n < 0 {
		log.Println("Decimal to hexadecimal error: the argument must be greater than zero.")
		return ""
	}

	if n == 0 {
		return "0"
	}

	hex := map[int64]int64{10: 65, 11: 66, 12: 67, 13: 68, 14: 69, 15: 70}

	s := ""

	for q := n; q > 0; q = q / 16 {

		m := q % 16

	if m > 9 && m < 16 {

		m = hex[m]

		s = fmt.Sprintf("%v%v", string(m), s)

		continue

		}

	s = fmt.Sprintf("%v%v", m, s)
	}

	return s
}

5.验证过程(完整代码)

//椭圆曲线数字签名算法ECDSA
package main

import(
	"fmt"
	"log"
	"math/big"
	"encoding/hex"
	"crypto/sha256"
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	
)

//生成私钥和公钥,生成的私钥为结构体ecdsa.PrivateKey的指针
func NewKeyPair()(ecdsa.PrivateKey,[]byte){
	//生成secp256椭圆曲线
	curve := elliptic.P256()
	//产生的是一个结构体指针,结构体类型为ecdsa.PrivateKey
	private,err := ecdsa.GenerateKey(curve, rand.Reader)
	if err != nil{
		log.Panic(err)
	}

	
	fmt.Printf("私钥:%x\n", private)
	fmt.Printf("私钥X:%x\n", private.X.Bytes())
	fmt.Printf("私钥Y:%x\n", private.Y.Bytes())
	fmt.Printf("私钥D:%x\n", private.D.Bytes())

	//x坐标与y坐标拼接在一起生成公钥
	pubKey := append(private.X.Bytes(),private.Y.Bytes()...)
	//打印公钥,公钥用16进制打印出来长度为128,包含了x轴坐标与y轴坐标。
	fmt.Printf("公钥:%x \n", pubKey)

	return *private, pubKey
}

//生成签名的DER格式
func MakeSignatureDerString(r,s string)string{
	//获取R和S的长度
	lenSigR := len(r)/2
	lenSigS := len(s)/2

	//计算DER序列的总长度
	lenSequence := lenSigR + lenSigS + 4

	//将10进制长度转16进制字符串
	strLenSigR := DecimalToHex(int64(lenSigR))
	strLenSigS := DecimalToHex(int64(lenSigS))
	strLenSequence := DecimalToHex(int64(lenSequence))

	// 拼凑DER编码
	derString := "30" + strLenSequence
	derString = derString + "02" + strLenSigR + r
	derString = derString + "02" + strLenSigS + s
	derString = derString + "01"

	return derString
}

//验证签名1
func VerifySignature1(pubKey,message []byte, r,s *big.Int)bool{
	curve := elliptic.P256()

	//公钥的长度
	keyLen := len(pubKey)

	//前一半为x轴坐标,后一半为y轴坐标
	x := big.Int{}
	y := big.Int{}
	x.SetBytes(pubKey[:(keyLen / 2)])
	y.SetBytes(pubKey[:(keyLen / 2)])
	rawPubKey := ecdsa.PublicKey{curve,&x,&y}

	//根据交易哈希、公钥、数字签名验证成功。ecdsa.Verify func Verify(pub *PublicKey,
	//hash []byte, r *big.Int, s *big.Int) bool
	res := ecdsa.Verify(&rawPubKey, message, r, s)

	return res	
}

//验证签名2
func VerifySignature2(pubKey, message []byte, r, s string) bool {
	curve := elliptic.P256()

	//公钥的长度
	keyLen := len(pubKey)

	//前一半为x轴坐标,后一半为y轴坐标
	x := big.Int{}
	y := big.Int{}
	x.SetBytes(pubKey[:(keyLen / 2)])
	y.SetBytes(pubKey[(keyLen / 2):])
	rawPubKey := ecdsa.PublicKey{curve, &x, &y}
	
	//根据交易哈希、公钥、数字签名验证成功。ecdsa.Verify func Verify(pub *PublicKey,
	//hash []byte, r *big.Int, s *big.Int) bool
	rint := big.Int{}
	sint := big.Int{}
	rByte, _ := hex.DecodeString(r)
	sByte, _ := hex.DecodeString(s)
	rint.SetBytes(rByte)
	sint.SetBytes(sByte)
	
	//fmt.Println("------", rint.SetBytes(rByte))
	//fmt.Println("------", sint.SetBytes(sByte))
	res := ecdsa.Verify(&rawPubKey, message, &rint, &sint)

	return res
}

func DecimalToHex(n int64) string {

	if n < 0 {
		log.Println("Decimal to hexadecimal error: the argument must be greater than zero.")
		return ""
	}

	if n == 0 {
		return "0"
	}

	hex := map[int64]int64{10: 65, 11: 66, 12: 67, 13: 68, 14: 69, 15: 70}

	s := ""

	for q := n; q > 0; q = q / 16 {

		m := q % 16

	if m > 9 && m < 16 {

		m = hex[m]

		s = fmt.Sprintf("%v%v", string(m), s)

		continue

		}

	s = fmt.Sprintf("%v%v", m, s)
	}

	return s
}

//验证过程
func main(){
	//1、生成签名
	fmt.Println("1、生成签名--------------------------")
	//调用函数生成私钥与公钥
	privKey,pubKey := NewKeyPair()

	//信息的哈希
	//msg := sha256.Sum256([]byte("hello world"))
	msg := sha256.Sum256([]byte("我爱Go语音,好好学习天天向上!"))
	
	//根据私钥和信息的哈希进行数字签名,产生r和s
	r,s,_ := ecdsa.Sign(rand.Reader,&privKey,msg[:])

	//生成r,s字符串
	fmt.Println("-----------------------------------")
	strSigR := fmt.Sprintf("%x",r)
	strSigS := fmt.Sprintf("%x",s)
	fmt.Println("r,s的10进制分别为:",r,s)
	fmt.Println("r,s的16进制分别为:",strSigR,strSigS)

	//r和s拼接在一起,形成数字签名的der格式
	signatureDer := MakeSignatureDerString(strSigR,strSigS)

	//打印数字签名的16进制显示
	fmt.Println("数字签名DER格式为:", signatureDer)
	fmt.Println()

	//2、签名验证过程
	fmt.Println("2、签名验证过程-------------------------------")
	res := VerifySignature1(pubKey, msg[:], r, s)
	fmt.Println("签名验证结果:" , res)
	
	res = VerifySignature2(pubKey, msg[:], strSigR, strSigS)
	fmt.Println("签名验证结果:" , res)
}

go run ecdsa.go
1、生成签名--------------------------
私钥:&{{{c0000540c0} 1da18c552d6ffd475afd08105fed0dfe2d54e5004348c03d8d3f2a52085ad58b c3b7be357933971eadfb6c0b7c386ceb4fa247b8de7bec7cf640aaaeedc3c5a5} 5a21d20e0965dc45685527d2455850513fa33af4e5f4f38c63ccdbdddf531c4a}
私钥X:1da18c552d6ffd475afd08105fed0dfe2d54e5004348c03d8d3f2a52085ad58b
私钥Y:c3b7be357933971eadfb6c0b7c386ceb4fa247b8de7bec7cf640aaaeedc3c5a5
私钥D:5a21d20e0965dc45685527d2455850513fa33af4e5f4f38c63ccdbdddf531c4a
公钥:1da18c552d6ffd475afd08105fed0dfe2d54e5004348c03d8d3f2a52085ad58bc3b7be357933971eadfb6c0b7c386ceb4fa247b8de7bec7cf640aaaeedc3c5a5
-----------------------------------
r,s的10进制分别为: 52728191750877498499034582730183912673898761759395273410353363098123716352490 93144752452882650126322260169752623811471464347533043453453550360746976309351
r,s的16进制分别为: 7493195391dec9a32cb1319ea7ca36d42227fe2a331ca4a6848c9eb2a0dd59ea cdee0fc7065f968e6a917600cfb15201602215ad84e42e3b591d8486edeb7067
数字签名DER格式为: 304402207493195391dec9a32cb1319ea7ca36d42227fe2a331ca4a6848c9eb2a0dd59ea0220cdee0fc7065f968e6a917600cfb15201602215ad84e42e3b591d8486edeb706701

2、签名验证过程-------------------------------
签名验证结果: false
签名验证结果: true

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Shinobi_Jack

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

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

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

打赏作者

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

抵扣说明:

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

余额充值