签名验证必须严格匹配算法、哈希与密钥类型:rsa.verifypkcs1v15仅验rsa-pkcs#1v1.5签名,ecdsa.verify仅验ecdsa签名,混用导致失败;哈希输出须完全一致,公钥需正确解析为rsa.publickey或ecdsa.publickey,ecdsa还需匹配曲线及asn.1编码格式。

签名验证函数必须明确指定哈希算法和密钥类型
Go 的 crypto 包不提供“通用签名验证”接口——你得自己选对哈希、填充方式、密钥格式。比如用 rsa.SignPKCS1v15 签的,就必须用 rsa.VerifyPKCS1v15 验;用 ecdsa.Sign 生成的,就得走 ecdsa.Verify 流程。混用会直接返回 x509: signature verification failed 或静默失败。
常见错误现象:crypto/rsa: verification error 往往不是密钥错,而是哈希对象没复位或签名字节长度不对(比如 RSA-2048 签名固定 256 字节,但传入了截断或补零后的数据)。
- 验签前,确保原始数据和签名时用的是**完全相同的哈希输出**(例如都用
sha256.Sum256(data).Sum(nil),而不是sha256.New().Write(data).Sum(nil)—— 后者多一个空字节) - 公钥必须是
*rsa.PublicKey或*ecdsa.PublicKey类型,不能是interface{}或 PEM 解码后未解析的[]byte - 如果公钥来自 PEM,记得用
pem.Decode提取 block,再用x509.ParsePKIXPublicKey或x509.ParsePKCS1PublicKey解析,别漏掉错误检查
ECDSA 验签要特别注意曲线参数和 ASN.1 编码格式
Go 默认用 ASN.1 DER 编码序列化 ECDSA 签名(r || s 拼接),而有些前端库(如 Web Crypto API)默认输出 IEEE P1363 格式(r || s 各占 32 字节)。直接传过去会报 crypto/ecdsa: invalid signature。
使用场景:前后端联调时,前端用 crypto.subtle.sign('ECDSA', key, data),后端 Go 必须确认签名格式。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- 若前端发来的是 P1363 格式(64 字节,r 和 s 各 32 字节),需手动转成 DER:
ecdsaSignatureToDER(rBytes, sBytes)(可用encoding/asn1.Marshal或第三方小工具) - 曲线必须匹配:secp256r1(即 prime256v1)对应
elliptic.P256(),secp384r1 对应elliptic.P384();用错曲线会导致crypto/ecdsa: invalid curve - 验签前建议先用
ecdsa.Validate检查公钥有效性,避免 panic
RSA 验签时填充方式和密钥长度必须与签名端严格一致
rsa.VerifyPKCS1v15 和 rsa.VerifyPSS 完全不兼容。用 PSS 签的,用 PKCS#1v1.5 验就是失败;反之亦然。而且 PSS 还要求传入 *rsa.PSSOptions,其中 SaltLength 必须和签名时一致(常见值是 rsa.PSSSaltLengthAuto 或具体字节数)。
性能影响:PSS 更安全但更慢;PKCS#1v1.5 更快但需确保输入数据无结构漏洞(比如不能直接验用户可控字符串)。
- 签名时用了
rsa.SignPKCS1v15(rand.Reader, privKey, crypto.SHA256, hash.Sum(nil)),验签就只能用rsa.VerifyPKCS1v15(pubKey, crypto.SHA256, hash.Sum(nil), sig) - 密钥长度影响签名长度:RSA-2048 → 256 字节签名;RSA-4096 → 512 字节。传入长度不符的
sig会直接 panic - 哈希摘要必须是原始字节,不是 base64 或 hex 字符串;别忘了把 hex 字符串用
hex.DecodeString转回[]byte
错误处理不能只看 err != nil
Go 的验签函数在失败时多数返回具体错误(如 crypto/rsa: verification error),但有些情况会返回 nil 错误却逻辑失败——比如传入空签名、空公钥、或哈希摘要长度与算法不匹配(SHA256 摘要 32 字节,但传了 64 字节),某些版本的 ecdsa.Verify 会静默返回 false。
容易被忽略的地方:没有校验公钥是否为 nil、签名长度是否为 0、哈希摘要是否为空,这些都可能导致后续 panic 或绕过验证。
- 务必在调用前做基础检查:
if len(sig) == 0 { return false, errors.New("empty signature") } - 对 RSA 公钥,可加
if pubKey.N == nil { return false, errors.New("invalid rsa public key") } - 对 ECDSA,建议用
elliptic.IsOnCurve(pubKey.X, pubKey.Y)初步验证点是否在曲线上
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










