package main
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/sha256"
"encoding/hex"
"fmt"
"log"
"math/big"
)
func main() {
//1.对需要签名的文件进行hash运算
data := "Oneck"
hashInstance := sha256.New()
hashInstance.Write([]byte(data))
hashed := hashInstance.Sum(nil)
//2.生成公钥私钥
privateKey, publicKeyBytes := NewKeyPair()
//3.生成签名的DER格式
derSignString := ECDSASign(hashed,privateKey)
fmt.Sprintf("签名信息为:\n",derSignString)
//4.验证签名
flag := ECDSAVerfy(publicKeyBytes,hashed,derSignString)
fmt.Println("签名验证结果",flag)
}
func NewKeyPair() (ecdsa.PrivateKey,[]byte) {
//- 生成椭圆曲线对象
curve := elliptic.P256()
//- 生成密钥对,返回私钥对象
privateKey, err := ecdsa.GenerateKey(curve,rand.Reader)
if err != nil {
log.Panic(err)
}
//- 编码生成公钥字节数组,参数是椭圆曲线、x坐标、y坐标
publicKeyBytes := elliptic.Marshal(curve,privateKey.X,privateKey.Y)
fmt.Printf("公钥 %x\n",publicKeyBytes)
return *privateKey,publicKeyBytes
}
//ECDSA数字签名
func ECDSASign(hashed []byte,privateKey ecdsa.PrivateKey) string {
//- 数字签名生成r、s的big.Int对象,参数是随机数、私钥、签名文件的哈希串
r,s,err := ecdsa.Sign(rand.Reader,&privateKey,hashed)
if err != nil {
return ""
}
//- 将r、s转成r、s字符串
strSigR := fmt.Sprintf("%x",r)
strSigS := fmt.Sprintf("%x",s)
if len(strSigR) == 63 {
strSigR = "0" + strSigR
}
if len(strSigS) == 63 {
strSigR = "0" + strSigS
}
fmt.Printf("r的16进制为:%s,长度为%d\n",strSigR,len(strSigR))
fmt.Printf("s的16进制为:%s,长度为%d\n",strSigS,len(strSigS))
//- r和s字符串凭借,形成数字签名的der格式
derString := MakeDerSign(strSigR,strSigS)
return derString
}
//生成数字签名的DER编码格式
func MakeDerSign(strR,strS string) string {
//获取R和S的长度
lenSigR := len(strR)/2 //16进制每两位1字节
lenSigS := len(strS)/2
//- 计算DER序列的总长度
len := lenSigR + lenSigS + 4
//- 将10进制长度转16进制字符串
strLenSigR := fmt.Sprintf("%x",int64(lenSigR))
strLenSigS := fmt.Sprintf("%x",int64(lenSigS))
strLen := fmt.Sprintf("%x",int64(len))
//- 拼凑DER编码格式
derString := "30" + strLen
derString += "02" + strLenSigR + strR
derString += "02" + strLenSigS + strS
derString += "01"
return derString
}
//ECDSA验证签名
func ECDSAVerfy(publicKeyBytes,hashed []byte,derSignString string) bool {
//公钥长度
keyLen := len(publicKeyBytes)
if keyLen != 65 {
return false
}
//- 生成椭圆曲线对象
curve := elliptic.P256()
//- 根据公钥字节数字,获取公钥中的x及y
publicKeyBytes = publicKeyBytes[1:]
x := new(big.Int).SetBytes(publicKeyBytes[:32])
y := new(big.Int).SetBytes(publicKeyBytes[32:])
//- 生成公钥对象
publicKey := ecdsa.PublicKey{curve,x,y}
//- 对der格式的签名进行解析,获取r、s字节数组后转成big.Int类型
rBytes,sBytes := ParseDERSignString(derSignString)
r := new(big.Int).SetBytes(rBytes)
s := new(big.Int).SetBytes(sBytes)
//- 验证签名。参数是共要对象、签名文件的哈希串、数字签名的r和s对象
return ecdsa.Verify(&publicKey,hashed,r,s)
}
//如传入是r/s调用此函数
func ECDSAVerfy1(publicKeyBytes,hashed,rBytes,sBytes []byte) bool {
//公钥长度
keyLen := len(publicKeyBytes)
if keyLen != 65 {
return false
}
//- 生成椭圆曲线对象
curve := elliptic.P256()
//- 根据公钥字节数字,获取公钥中的x及y
publicKeyBytes = publicKeyBytes[1:]
x := new(big.Int).SetBytes(publicKeyBytes[:32])
y := new(big.Int).SetBytes(publicKeyBytes[32:])
//- 生成公钥对象
publicKey := ecdsa.PublicKey{curve,x,y}
r := new(big.Int).SetBytes(rBytes)
s := new(big.Int).SetBytes(sBytes)
//- 验证签名。参数是共要对象、签名文件的哈希串、数字签名的r和s对象
return ecdsa.Verify(&publicKey,hashed,r,s)
}
func ParseDERSignString(derString string) (rBytes,sBytes []byte) {
derBytes,_ := hex.DecodeString(derString)
rBytes = derBytes[4:36]
sBytes = derBytes[len(derBytes) - 33 : len(derBytes) - 1]
return
}