Golang中ECDSA签名的实现与使用

Golang中ECDSA签名的实现与使用 如何在Go中实现这段Python代码?

from ecdsa import SigningKey  

signing_key = SigningKey.from_pem(data) 

signature = signing_key.sign(to_sign_as_bytes, hashfunc=sha256, sigencode=ecdsa.util.sigencode_der) 

7 回复

有趣。在我看来这似乎是一条死胡同。

更多关于Golang中ECDSA签名的实现与使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


抱歉,可能是因为链接中的文档说明它使用的是 SHA-512,而你的代码列出的是 SHA-256。

crypto/ecdsa 包中有一个示例。

是的,我使用了相关的包。但我得到了一个不同的签名。我使用了Go的ecdsa.Sign()

func main() {
    fmt.Println("hello world")
}

好的,我可以尝试一下。感谢您指出这一点。

我看到了 ecdsa.go 文件的第 215 行

md := sha512.New()

ECDSA 代码是可用的。维基百科上列出的算法仅在第一步中提到了哈希函数。修改代码以使用 SHA256 可能足够简单。

// 代码示例
func main() {
    fmt.Println("hello world")
}

在Go中实现ECDSA签名可以使用crypto/ecdsacrypto/x509包。以下是等效的Go代码实现:

package main

import (
	"crypto/ecdsa"
	"crypto/sha256"
	"crypto/x509"
	"encoding/asn1"
	"encoding/pem"
	"errors"
	"math/big"
)

// 定义ASN.1结构体用于DER编码
type ecdsaSignature struct {
	R, S *big.Int
}

func signWithECDSA(pemData []byte, message []byte) ([]byte, error) {
	// 解析PEM格式的私钥
	block, _ := pem.Decode(pemData)
	if block == nil {
		return nil, errors.New("failed to parse PEM block")
	}

	// 解析私钥
	privKey, err := x509.ParseECPrivateKey(block.Bytes)
	if err != nil {
		return nil, err
	}

	// 计算消息的哈希
	hash := sha256.Sum256(message)

	// 使用私钥签名
	r, s, err := ecdsa.Sign(nil, privKey, hash[:])
	if err != nil {
		return nil, err
	}

	// 将签名编码为DER格式
	signature := ecdsaSignature{R: r, S: s}
	derSignature, err := asn1.Marshal(signature)
	if err != nil {
		return nil, err
	}

	return derSignature, nil
}

// 使用示例
func main() {
	// PEM格式的私钥(示例)
	pemKey := `-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIIBp+QpYpXKX9rJ5ZQJmJvLkKzN6tW7b8fG3qHj4oOoAoGCCqGSM49
AwEHoUQDQgAE1LJk4pW+5WQn5J5Z5Z5Z5Z5Z5Z5Z5Z5Z5Z5Z5Z5Z5Z5Z5Z5Z5Z
5Z5Z5Z5Z5Z5Z5Z5Z5Z5Z5Z5Z5Z5Z5Z5Z5Z5Z5Z5Z5Z5Z5Z5Z5Z5Z5Z5Z5Z5Z5Z
-----END EC PRIVATE KEY-----`

	// 要签名的消息
	message := []byte("Hello, ECDSA!")

	// 执行签名
	signature, err := signWithECDSA([]byte(pemKey), message)
	if err != nil {
		panic(err)
	}

	// 输出DER格式的签名
	println("DER Signature:", signature)
}

如果需要从文件读取PEM密钥,可以这样实现:

func signFromPEMFile(filename string, message []byte) ([]byte, error) {
	// 读取PEM文件
	pemData, err := os.ReadFile(filename)
	if err != nil {
		return nil, err
	}

	return signWithECDSA(pemData, message)
}

对于验证签名,可以使用以下代码:

func verifyECDSA(pemData []byte, message, signature []byte) (bool, error) {
	// 解析PEM格式的公钥
	block, _ := pem.Decode(pemData)
	if block == nil {
		return false, errors.New("failed to parse PEM block")
	}

	// 解析公钥
	pubKey, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		return false, err
	}

	ecdsaPubKey, ok := pubKey.(*ecdsa.PublicKey)
	if !ok {
		return false, errors.New("not an ECDSA public key")
	}

	// 计算消息哈希
	hash := sha256.Sum256(message)

	// 解析DER签名
	var sig ecdsaSignature
	_, err = asn1.Unmarshal(signature, &sig)
	if err != nil {
		return false, err
	}

	// 验证签名
	return ecdsa.Verify(ecdsaPubKey, hash[:], sig.R, sig.S), nil
}

这段Go代码实现了与Python示例相同的功能:从PEM格式的ECDSA私钥加载签名密钥,使用SHA256哈希函数对数据进行签名,并将结果编码为DER格式。

回到顶部