使用phpseclib验证RSA-PSS

huangapple go评论153阅读模式
英文:

Verify RSA-PSS With phpseclib

问题

我尝试验证在Golang中使用phpseclib v3库签名的RSA-PSS签名,但PHP验证一直出错。但让我困惑的是,当我尝试在PHP中签名该签名并在Golang和PHP中都进行验证时,它可以正常工作。

这是我在Golang中用于签名和验证签名的代码:

签名:

rng := rand.Reader
rsa.SignPSS(rng, key, crypto.SHA256, digest, nil)

验证签名:

rsa.VerifyPSS(key, crypto.SHA256, digest, signature, nil)

这是在PHP中验证和签名签名的代码:

验证签名:

$key = RSA::loadPublicKey('the key');
$result = $key->withHash('sha256')->withMGFHash('sha256')->verify($message, $signature);

签名:

$key = RSA::loadPrivateKey('the key');
$key = $private->withPadding(RSA::SIGNATURE_PSS);
$signature = $private->withHash('sha256')->withMGFHash('sha256')->sign($message);

注意
签名值以加密的base64格式返回,我在验证签名之前已解密该值。

有人可以解释这是如何发生的吗?我应该怎么做才能使它在两者中都正常工作?

英文:

So i tried to verify rsa-ps signature that signed in golang with php library phpseclib v3. The php verification keep getting me an error. But what makes me confuse is when i try sign the signature in php and verify that in both golang and php it works.

this is the code that i use for sign and verify the signature in golang

Sign signature

rng := rand.Reader
rsa.SignPSS(rng, key, crypto.SHA256, digest, nil)

Verify signature

rsa.VerifyPSS(key, crypto.SHA256, digest, signature, nil)

and this is the code to verify and sign the signature in php

Verify signature

$key = RSA::loadPublicKey('the key');
$result = $key->withHash('sha256')->withMGFHash('sha256')->verify($message, $signature);

Sign signature

$key = RSA::loadPrivateKey('the key');
$key = $private->withPadding(RSA::SIGNATURE_PSS);
$signature = $private->withHash('sha256')->withMGFHash('sha256')->sign($message);

NOTE
The value of signature return in encrypted base64 and i already decrypt the value before verify the signature

Anyone can explain hows that happen ? and what should i do to make it works for both ?

答案1

得分: 3

PSS允许指定各种参数(参见RFC8017,9.1.1节):摘要、掩码生成函数(实际上,通常应用MGF1并且只能指定其摘要),以及盐长度。

在PHP中的验证失败,因为虽然你明确指定了摘要(以使它们在两个代码中相同),但你使用了库的默认值作为盐长度,这些默认值是不同的。因此,这两个代码不兼容:

  • 在你的Go代码中,在SignPSS()调用中,第五个参数被指定为nil,所以saltLength()给出了PSSSaltLengthAuto,从而应用了最大可能的盐长度。最大可能的盐长度是以字节为单位的(例如,使用2048位签名/密钥长度和SHA256作为摘要:256 - 32 - 2字节)。

  • 在PHP代码中,默认情况下使用摘要输出长度(SHA256为32字节)作为盐长度,参见这里

因此,为了使PHP代码能够验证Go代码的签名,必须使用withSaltLength()将盐长度明确设置为最大值:

$key = RSA::load($pubKey);
$result = 	$key
			->withHash('sha256')                // 默认(在V3中)
			->withMGFHash('sha256')             // 默认(在V3中)
			->withSaltLength(256 - 32 - 2)		// 修复!用你的签名/密钥长度(以字节为单位)替换256
			->verify($message, $signature);
print($result ? 'valid signature' : 'invalid signature'); // 有效签名

为了完整起见,最大盐长度也可以通过以下方式确定:

$key->getLength()/8 - $key->getHash()->getLengthInBytes() - 2

或者,可以在Go代码中将默认的PHP代码中应用的摘要输出长度(SHA256为32字节)用作盐长度:

var ops rsa.PSSOptions
ops.SaltLength = rsa.PSSSaltLengthEqualsHash
signature, err := rsa.SignPSS(rng, keyPkcs8, crypto.SHA256, digest, &ops)

实际上,通常会将摘要输出长度用作盐长度。

英文:

PSS allows the specification of various parameters (s. RFC8017, 9.1.1): Digest, mask generation function (in practice, MGF1 is applied and only its digest can be specified) and salt length.
The verification with PHP fails because although you specify the digests explicitly (so that they are identical in both codes), you use the library defaults for the salt length, which are different. Therefore, the two codes are not compatible:

  • In your Go code, in the SignPSS() call the 5th parameter is specified as nil, so saltLength() gives PSSSaltLengthAuto, resulting in the maximum possible salt length being applied.
    The maximum possible salt length is signature length - digest output length - 2 in bytes (e.g. with a 2048 bits signature / key length and SHA256 as digest: 256 - 32 - 2 bytes).

  • In the PHP code, the digest output length (32 bytes for SHA256) is used by default for the salt length, s. here.

Therefore, in order for the PHP code to verify the signature of the Go code, the salt length must be explicitly set to the maximum size using withSaltLength():

$key = RSA::load($pubKey);
$result = 	$key
			->withHash('sha256')                // default (in V3)
			->withMGFHash('sha256')             // default (in V3)
			->withSaltLength(256 - 32 - 2)		// Fix! Replace 256 with your signature / key length in bytes
			->verify($message, $signature);
print($result ? 'valid signature' : 'invalid signature'); // valid signature

For completeness: The maximum salt length can also be determined with:

$key->getLength()/8 - $key->getHash()->getLengthInBytes() - 2

Alternatively, the digest output length (32 bytes for SHA256), which is applied by default in the PHP code, can be used as salt length in the Go code:

var ops rsa.PSSOptions
ops.SaltLength = rsa.PSSSaltLengthEqualsHash
signature, err := rsa.SignPSS(rng, keyPkcs8, crypto.SHA256, digest, &ops)

In practice, the digest output length is often used as salt length.

huangapple
  • 本文由 发表于 2023年8月9日 12:04:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/76864498-2.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定