You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

跨OpenSSL与Golang 1.18无法验证RSA-PSS签名问题

跨OpenSSL与Go的RSA-PSS签名双向验证失败问题

问题场景

  • Bash中通过OpenSSL生成RSA密钥和RSA-PSS签名,OpenSSL自身验证通过,但Go验证该签名时触发crypto/rsa: verification error panic
  • Go生成的RSA-PSS签名可通过自身验证,但OpenSSL验证时提示Verification Failure

OpenSSL操作步骤

openssl genrsa -out key.pem 4096
openssl rsa -in key.pem -pubout > key.pub

truncate -size=16 zeroes.bin

openssl dgst -sign key.pem -keyform PEM -sha512 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:64 -out signature.bin -binary zeroes.bin

原Go验证代码(main.go)

package main

import (
    "crypto"
    "crypto/rand"
    "crypto/rsa"
    "crypto/sha512"
    "crypto/x509"
    "encoding/pem"
    "fmt"
    "io/ioutil"
)

func main() {
    privatePem, _ := ioutil.ReadFile("key.pem")
    privateBlock, _ := pem.Decode(privatePem)
    if privateBlock == nil {
        panic("Failed to decode private pem")
    }
    privateKey, err := x509.ParsePKCS1PrivateKey(privateBlock.Bytes)
    if err != nil {
        panic(err)
    }

    h := sha512.New()
    h.Write(make([]byte, 16))
    zeroes := h.Sum(nil)

    signature, err := rsa.SignPSS(rand.Reader, privateKey, crypto.SHA512, zeroes, &rsa.PSSOptions{
        SaltLength: rsa.PSSSaltLengthEqualsHash, // should be 64 for sha512
    })
    if err != nil {
        panic(err)
    }
    ioutil.WriteFile("signature.go.bin", signature, 0600)

    err = rsa.VerifyPSS(&privateKey.PublicKey, crypto.SHA512, zeroes, signature, &rsa.PSSOptions{
        SaltLength: rsa.PSSSaltLengthEqualsHash,
    })
    if err != nil {
        panic(err)
    }

    fmt.Println("Verified go signature.")

    opensslSignature, _ := ioutil.ReadFile("signature.bin")
    err = rsa.VerifyPSS(&privateKey.PublicKey, crypto.SHA512, zeroes, opensslSignature, &rsa.PSSOptions{
        SaltLength: rsa.PSSSaltLengthEqualsHash,
    })
    if err != nil {
        panic(err)
    }

    fmt.Println("Not getting here -- crypto/rsa: verification error")
}

问题原因与修复方案

1. 签名输入的哈希处理逻辑差异

OpenSSL的dgst -sign命令会自动对输入文件做哈希计算,再用私钥签名哈希值;而Go的rsa.SignPSS函数要求传入的是原始数据(函数内部会自动计算指定哈希),原Go代码提前对原始数据做了哈希,导致两边签名的输入哈希不一致。

修复哈希计算部分

将原代码中提前计算哈希的逻辑改为直接使用原始16字节数据:

// 替换原哈希计算代码,直接使用原始16字节数据
zeroes := make([]byte, 16)

2. 确认参数一致性

SHA512哈希长度为64字节,OpenSSL指定的rsa_pss_saltlen:64与Go中rsa.PSSSaltLengthEqualsHash参数完全匹配;两边默认的MGF1哈希函数均与签名哈希(SHA512)一致,无需额外配置。

完整修复后的Go代码

package main

import (
    "crypto"
    "crypto/rand"
    "crypto/rsa"
    "crypto/sha512"
    "crypto/x509"
    "encoding/pem"
    "fmt"
    "io/ioutil"
)

func main() {
    privatePem, err := ioutil.ReadFile("key.pem")
    if err != nil {
        panic(err)
    }
    privateBlock, _ := pem.Decode(privatePem)
    if privateBlock == nil {
        panic("Failed to decode private pem")
    }
    privateKey, err := x509.ParsePKCS1PrivateKey(privateBlock.Bytes)
    if err != nil {
        panic(err)
    }

    // 使用原始16字节数据,由SignPSS内部处理SHA512哈希
    zeroes := make([]byte, 16)

    // 生成Go签名
    signature, err := rsa.SignPSS(rand.Reader, privateKey, crypto.SHA512, zeroes, &rsa.PSSOptions{
        SaltLength: rsa.PSSSaltLengthEqualsHash,
    })
    if err != nil {
        panic(err)
    }
    err = ioutil.WriteFile("signature.go.bin", signature, 0600)
    if err != nil {
        panic(err)
    }

    // 验证Go自身签名
    err = rsa.VerifyPSS(&privateKey.PublicKey, crypto.SHA512, zeroes, signature, &rsa.PSSOptions{
        SaltLength: rsa.PSSSaltLengthEqualsHash,
    })
    if err != nil {
        panic(err)
    }
    fmt.Println("Verified go signature.")

    // 验证OpenSSL生成的签名
    opensslSignature, err := ioutil.ReadFile("signature.bin")
    if err != nil {
        panic(err)
    }
    err = rsa.VerifyPSS(&privateKey.PublicKey, crypto.SHA512, zeroes, opensslSignature, &rsa.PSSOptions{
        SaltLength: rsa.PSSSaltLengthEqualsHash,
    })
    if err != nil {
        panic(err)
    }
    fmt.Println("Verified OpenSSL signature successfully!")
}

验证Go生成的签名在OpenSSL中通过

执行以下命令验证Go生成的signature.go.bin:

openssl dgst -verify key.pub -keyform PEM -sha512 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:64 -signature signature.go.bin zeroes.bin

此时会返回Verified OK。

内容的提问来源于stack exchange,提问作者Kent Thompson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 04:50:34