Go实现ECDSA P384签名与OpenSSL兼容问题求助
Go ECDSA P384签名与OpenSSL兼容问题解决方法
问题根源
你的代码和OpenSSL命令存在两个关键不兼容点:
- 哈希算法不匹配:OpenSSL用的是SHA-384,但你的Go代码用了SHA-512,P384椭圆曲线要求使用SHA-384作为哈希算法
- S值未规范化:OpenSSL会自动将签名中的S值调整到曲线阶的一半以下(符合SEC 1标准),而Go原生
ecdsa.Sign不会做这个处理
修正后的签名代码
import ( "crypto/ecdsa" "crypto/rand" "crypto/sha384" "encoding/asn1" "math/big" ) func signECDSA(privateKey *ecdsa.PrivateKey, data []byte) ([]byte, error) { // 改用SHA-384哈希,和OpenSSL命令保持一致 hash := sha384.Sum384(data) r, s, err := ecdsa.Sign(rand.Reader, privateKey, hash[:]) if err != nil { return nil, err } // 规范化S值:确保S <= 曲线阶的一半 curveOrder := privateKey.Curve.Params().N halfOrder := new(big.Int).Div(curveOrder, big.NewInt(2)) if s.Cmp(halfOrder) > 0 { s.Sub(curveOrder, s) } // 序列化为ASN.1 DER格式 sig := struct { R, S *big.Int }{r, s} signatureBytes, err := asn1.Marshal(sig) if err != nil { return nil, err } return signatureBytes, nil }
关键改动说明
- 哈希算法替换:将
sha512.Sum512改为sha384.Sum384,匹配OpenSSL命令中的-sha384参数 - S值规范化:检查S值是否大于曲线阶的一半,如果是则用曲线阶减去S值,生成符合SEC 1标准的签名,确保和OpenSSL行为一致
验证方法
用修正后的代码生成签名后,直接使用你原来的OpenSSL验证命令即可通过:
openssl dgst -sha384 -verify public_key.pem -signature signed_data input_data
内容的提问来源于stack exchange,提问作者M. Glushkin
相关产品推荐
相关产品推荐

