使用phpseclib验证Go生成的RSA-PSS签名失败问题求助
RSA-PSS签名跨Go与phpseclib v3验证失败的原因及解决方案
核心问题分析
- 填充方式未显式指定:phpseclib v3默认使用PKCS#1 v1.5填充进行签名/验证,而你的Go代码明确使用RSA-PSS填充,两者不匹配导致验证失败。
- 哈希输入逻辑不一致:Go的
rsa.SignPSS接收的是消息的SHA256哈希值作为输入,而phpseclib默认的verify方法会自动对传入的原始消息计算哈希,若未对齐这一逻辑,会导致验证时的哈希输入不匹配。
修复步骤
1. 修正PHP验证代码,指定PSS填充
在PHP验证代码中添加withPadding(RSA::SIGNATURE_PSS),明确使用PSS填充:
$key = RSA::loadPublicKey('the key'); $result = $key->withPadding(RSA::SIGNATURE_PSS) // 关键:指定PSS填充 ->withHash('sha256') ->withMGFHash('sha256') ->verify($message, $signature);
2. 对齐哈希输入逻辑
如果你的Go代码是先计算消息的SHA256哈希,再传入rsa.SignPSS(如下):
message := []byte("your original message") digest := sha256.Sum256(message) signature, err := rsa.SignPSS(rand.Reader, key, crypto.SHA256, digest[:], nil)
那么PHP端不能直接传入原始消息调用verify(否则会重复计算哈希),而应使用verifyRaw方法直接传入消息的哈希值:
$key = RSA::loadPublicKey('the key'); // 计算原始消息的SHA256二进制哈希 $digest = hash('sha256', $message, true); $result = $key->withPadding(RSA::SIGNATURE_PSS) ->withHash('sha256') ->withMGFHash('sha256') ->verifyRaw($digest, $signature);
3. 显式指定盐长度(可选但推荐)
Go的rsa.SignPSS默认使用与哈希长度相等的盐(SHA256对应32字节),phpseclib v3可显式指定该配置以确保完全兼容:
$result = $key->withPadding(RSA::SIGNATURE_PSS) ->withHash('sha256') ->withMGFHash('sha256') ->withSaltLength(RSA::SALT_LENGTH_EQUALS_HASH) // 匹配Go默认盐长度 ->verifyRaw($digest, $signature);
验证兼容性
调整后,Go生成的签名应能在PHP端正常验证,同时保持PHP生成的签名在两端的兼容性。
内容的提问来源于stack exchange,提问作者Devanser
相关产品推荐
相关产品推荐

