Go标准库crypto/rsa签名验签必须先哈希再操作,且哈希算法、密钥格式(PKCS#1/PKCS#8)、公钥类型(*rsa.PublicKey)、签名长度须严格匹配,否则VerifyPKCS1v15返回crypto.ErrVerification或panic。

Go 标准库的 crypto/rsa 支持 RSA 签名与验签,但直接调用 SignPKCS1v15 或 VerifyPKCS1v15 容易出错——常见问题是哈希不匹配、密钥格式错误、签名长度校验失败,或误用私钥验签(典型反模式)。
签名前必须先哈希,且哈希算法要和 SignPKCS1v15 的 hash 参数严格一致
Go 不允许你传原始数据给 SignPKCS1v15;它要求你传入已计算好的哈希摘要(hash.Hash 接口),且该哈希类型必须与函数参数中指定的 crypto.Hash 值完全对应。否则会 panic:crypto: requested hash function is not available。
- 用
sha256.New()计算原文哈希后,必须传crypto.SHA256给SignPKCS1v15,不能写成crypto.SHA256.String()或硬编码字符串 - 如果原文较大,别用
hash.Sum(nil)拿原始字节再重哈希——应直接用hash.Sum(nil)返回的切片,它是完整摘要值 - 示例关键片段:
h := sha256.New() h.Write([]byte("hello")) digest := h.Sum(nil) sig, err := rsa.SignPKCS1v15(rand.Reader, privKey, crypto.SHA256, digest[:])
验签时公钥必须是 *rsa.PublicKey 类型,且需从私钥正确导出或独立解析
很多人把 *rsa.PrivateKey 当作公钥传给 VerifyPKCS1v15,导致 panic:crypto/rsa: verification error。Go 中公钥不是私钥的子集字段,而是独立结构体。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- 若从私钥获取:用
privKey.Public().(*rsa.PublicKey),注意类型断言,失败会 panic - 若从 PEM 解析公钥:必须用
pem.Decode后调用x509.ParsePKIXPublicKey(不是ParseCertificate),否则返回*x509.Certificate无法直接用于验签 - 验签时传入的哈希摘要字节必须和签名时完全一致(包括长度和内容),哪怕多一个空格都会失败
私钥加载失败常因 PEM Block type 错误或密码为空时误调 DecryptPEMBlock
读取私钥文件最常卡在 x509.ParsePKCS1PrivateKey 或 x509.ParsePKCS8PrivateKey 返回 nil。根本原因通常是 PEM 头尾不匹配,比如用 -----BEGIN RSA PRIVATE KEY----- 却调用了 ParsePKCS8PrivateKey。
立即学习“go语言免费学习笔记(深入)”;
- OpenSSL 生成的默认私钥是 PKCS#1(对应
ParsePKCS1PrivateKey);加了-aes256的则需先用x509.DecryptPEMBlock解密,且密码为空字符串时不能跳过解密步骤(某些版本会静默失败) - 推荐统一用 PKCS#8 格式:生成命令为
openssl pkcs8 -topk8 -inform PEM -outform PEM -in key.pem -nocrypt,然后用ParsePKCS8PrivateKey - 检查 PEM block type:用
pem.Decode后打印block.Type,确认是RSA PRIVATE KEY还是PRIVATE KEY
真正容易被忽略的是:RSA 签名本身不包含算法标识,验签方必须和签名方约定好哈希算法、填充方式(PKCS#1 v1.5)、密钥长度。这些信息不会随签名传输,一旦错配,错误表现往往只是 “verification error”,没有更多上下文——你得自己核对每一步的哈希对象、函数参数、密钥来源是否闭环一致。

















