使用phpseclib验证RSA-PSS

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

Verify RSA-PSS With phpseclib

问题

所以我尝试使用php库phpseclib v3验证用golang签名的rsa-ps签名。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()调用中,第5个参数被指定为nil,因此saltLength()会返回PSSSaltLengthAuto,从而应用最大可能的盐长度。
    最大可能的盐长度为签名长度 - 摘要输出长度 - 2字节(例如,对于2048位的签名/密钥长度和SHA256作为摘要:256 - 32 - 2字节)。

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

因此,为了使PHP代码能够验证Go代码的签名,必须使用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

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

$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.html
匿名

发表评论

匿名网友

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

确定