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