Golang与Java生成的PKCS#1v15 RSA签名不一致,求解决建议
RSA签名不一致问题解决(Java vs Golang)
在实现基于PKCS#1v15的RSA签名时,先对原始数据做MD5哈希转十六进制字符串,再用SHA256WithRSA签名,Golang生成的签名始终和Java版本不一致,导致服务器返回签名错误。
问题根源
1. SHA256摘要处理逻辑不一致
Java中SHA256WithRSA签名算法的逻辑是:先对要签名的字节数据计算SHA256摘要,再用RSA PKCS#1v15对该摘要签名。
而你的Golang代码中,直接将MD5十六进制字符串的字节传入rsa.SignPKCS1v15并指定crypto.SHA256参数——这个参数的含义是「传入的字节已经是SHA256摘要」,所以Go会直接对这些字节做RSA签名,跳过了SHA256哈希步骤,和Java的逻辑完全相反。
2. Base64 URL安全编码的填充处理差异
Java的Base64.encodeBase64URLSafeString会自动去除Base64编码末尾的填充字符=,而Golang默认的base64.URLEncoding.EncodeToString会保留这些填充字符,导致最终的签名字符串不一致。
修正后的Golang代码
import ( "crypto/md5" "crypto/rand" "crypto/rsa" "crypto/sha256" "crypto" "encoding/base64" "encoding/hex" "fmt" ) func GetSignature(data []byte, pk *rsa.PrivateKey) (string, error) { // 第一步:MD5哈希转十六进制字符串,和Java逻辑对齐 m := md5.New() _, err := m.Write(data) if err != nil { return "", err } encoded := hex.EncodeToString(m.Sum(nil)) fmt.Println(encoded) // 第二步:对十六进制字符串的UTF-8字节计算SHA256摘要,补全Java中SHA256WithRSA的哈希步骤 sha256Hash := sha256.New() _, err = sha256Hash.Write([]byte(encoded)) if err != nil { return "", err } sha256Digest := sha256Hash.Sum(nil) // 第三步:用RSA PKCS#1v15签名SHA256摘要 signature, err := rsa.SignPKCS1v15(rand.Reader, pk, crypto.SHA256, sha256Digest) if err != nil { return "", err } // 第四步:使用无填充的Base64 URL安全编码,对齐Java的处理逻辑 return base64.URLEncoding.WithPadding(base64.NoPadding).EncodeToString(signature), nil }
验证要点
- 确保Java和Golang使用同一套RSA私钥,且私钥格式一致(比如均为PKCS#8格式)。
- 打印MD5转十六进制的字符串,确认两者完全一致(排除数据编码差异)。
- 打印签名前的SHA256摘要,确认Java和Golang计算结果一致。
内容的提问来源于stack exchange,提问作者Tselmuun
相关产品推荐
相关产品推荐

