Go椭圆曲线数字签名、验证

Gail ·
更新时间:2024-09-21
· 959 次阅读

椭圆曲线数字签名及验证 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() { //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 }

在这里插入图片描述


作者:Oneck_peter



GO 数字签名

需要 登录 后方可回复, 如果你还没有账号请 注册新账号