密码技术--椭圆曲线算法EDCSA数字签名及Go语言应用

1.生成秘钥对并写入磁盘文件

1.使用ecdsa生成秘钥对

2.将私钥写入磁盘

  • 使用x509进行反序列化
  • 将得到的切片字符串放到pem.Block结构体中
  • 使用pem编码

3.将公钥写入磁盘

  • 从私钥中得到公钥
  • 使用x509进行序列化
  • 将得到的切片字符串放入pem.Block结构体中
  • 使用pem编码

2.使用私钥进行数字签名

1.打开私钥文件,将内容读出来

2.使用pem进行数据解码

3.使用x509对数据还原

4.对原始数据进行哈希运算

5.进行数字签名
func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error)
6.返回值为指针,因此需要将该地址指向内存中的数据进行序列话

3.使用公钥验证数字签名

1.打开公钥文件,读出数据

2.使用pem进行解码

3.使用x509进行公钥数据还原
func ParsePKIXPublicKey(derBytes []byte) (pub interface{}, err error)

4.由于上一步返回的是一个接口类型,因此需要进行类型断言,将接口类型转换为公钥

5.对原始数据进行哈希运算

6.验签

4.go中应用

package main

import (
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"crypto/x509"
	"encoding/pem"
	"os"
	"crypto/sha256"
	"math/big"
)

func GenerateEcdsaKey () {
	//1.使用ecdsa生成秘钥对
	privateKey, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
	if err != nil {
		panic(err)
	}
	//2.将私钥写入磁盘
	//* 使用x509进行反序列化
	ecPrivateKey, err := x509.MarshalECPrivateKey(privateKey)
	if err != nil {
		panic(err)
	}
	//* 将得到的切片字符串放到pem.Block结构体中
	block := pem.Block{
		Type:    "ecdsa private key",
		Headers: nil,
		Bytes:   ecPrivateKey,
	}
	//* 使用pem编码
	file, err := os.Create("ecPrivate.pem")
	if err != nil {
		panic(err)
	}
	defer file.Close()
	err = pem.Encode(file, &block)
	if err != nil {
		panic(err)
	}
	//3.将公钥写入磁盘
	//* 从私钥中得到公钥
	publicKey := privateKey.PublicKey
	//* 使用x509进行序列化
	ecPublicKey, err := x509.MarshalPKIXPublicKey(&publicKey)
	if err != nil {
		panic(err)
	}
	//* 将得到的切片字符串放入pem.Block结构体中
	block = pem.Block{
		Type:    "ecdsa public key",
		Headers: nil,
		Bytes:   ecPublicKey,
	}
	//* 使用pem编码
	file, err = os.Create("ecPublic.pem")
	if err != nil {
		panic(err)
	}
	defer file.Close()
	pem.Encode(file, &block)
}

//签名
func SignECDSA (plainText []byte, priFileName string) (rText, sText []byte) {
	//1.打开私钥文件,将内容读出来
	file, err := os.Open(priFileName)
	if err != nil {
		panic(err)
	}
	defer file.Close()
	fileInfo, err := file.Stat()
	if err != nil {
		panic(err)
	}
	buf := make([]byte, fileInfo.Size())
	_, err = file.Read(buf)
	if err != nil {
		panic(err)
	}
	//2.使用pem进行数据解码
	block, _ := pem.Decode(buf)
	//3.使用x509对数据还原
	privateKey, err := x509.ParseECPrivateKey(block.Bytes)
	if err != nil {
		panic(err)
	}
	//4.对原始数据进行哈希运算
	hashText := sha256.Sum256(plainText)
	//5.进行数字签名
	var r, s *big.Int //注意这里
	r, s, err = ecdsa.Sign(rand.Reader, privateKey, hashText[:])
	if err != nil {
		panic(err)
	}
	//6.返回值为指针,因此需要将该地址指向内存中的数据进行序列话
	rText, err = r.MarshalText()
	if err != nil {
		panic(err)
	}
	sText, err = s.MarshalText()
	if err != nil {
		panic(err)
	}
	return rText,sText
}

//验签
func VerifyECDSA (plainText, rText, sText []byte, pubFileName string) bool {
	//1.打开公钥文件,读出数据
	file, err := os.Open(pubFileName)
	if err != nil {
		panic(err)
	}
	defer file.Close()
	fileInfo, err := file.Stat()
	if err != nil {
		panic(err)
	}
	buf := make([]byte, fileInfo.Size())
	_, err = file.Read(buf)
	if err != nil {
		panic(err)
	}
	//2.使用pem进行解码
	block, _ := pem.Decode(buf)
	//3.使用x509进行公钥数据还原
	pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		panic(err)
	}
	//4.由于上一步返回的是一个接口类型,因此需要进行类型断言,将接口类型转换为公钥
	publicKey := pubInterface.(*ecdsa.PublicKey)
	//5.对原始数据进行哈希运算
	hashText := sha256.Sum256(plainText)
	//6.验签
	var r, s big.Int
	r.UnmarshalText(rText)
	s.UnmarshalText(sText)
	res := ecdsa.Verify(publicKey, hashText[:], &r, &s)
	return res
}
上一篇:[转载保存] openssl显示证书信息


下一篇:OpenSSL发布了2个高危漏洞的补丁程序