【问题标题】:rsacryptoserviceprovider.VerifyData always returns falsersacryptoserviceprovider.VerifyData 始终返回 false
【发布时间】:2017-10-07 13:02:29
【问题描述】:

下面是我的 C# 程序,它验证来自使用 phpseclib 的 php 脚本的响应

static void Main(string[] args)
        {

            var payment =
                "VUQxMzE1MTg0OTk0MDM2MzIyMDJ8VDAwMDAxN0kxMFVEMTMxNTE4NDk5NDAzNjMyMjAyfDIwMTctMTAtMDd8MHxwYXltZW50IHN1Y2Nlc3NmdWx8MjAyNTQ=";
            var signature =
                "V0T9ZedZW8oB9uy4PazRIxWHvJ7rR+FVtnGjUy30mSKqgmEceZWE1aBvkQWeG4ERjAXHjsRge0D0MlHd9zvXjrLog+G5nWBHIu52O0srCd9d71JVztMQy8fV5oSnRPtlUpgdmn8QDnJ27XrbaHzNxnFyybTQhmbfxkT0oJ0MEOk=";

            var sigByte = Convert.FromBase64String(signature);
            var payBite = Convert.FromBase64String(payment);

            Verify(payBite, sigByte);
        }

        public static bool Verify(byte[] payment, byte[] signature)
        {
            var key = Resources.PublicKey;
            var cipher = Crypto.DecodeX509PublicKey(key);

            var res = cipher.VerifyData(payment, "SHA256", signature);
            return res;
        }

使用的公钥如下:

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDSiXzUuH9ePZgSLYrzZ0qhta25
HCb+WG48wIKUl+cQNC/Fl/KZG2cSwRXdo8KZLVWWO5qwzplfTWEylg4IqRA48rYY
f/b+Y7QhORKeAws4pttLZJBbh1mIbZ9HXfQ+zBjP+zfJZ1YjSFs2uZdwSt1itUcJ
/GQFct8GoUevNELG7wIDAQAB
-----END PUBLIC KEY-----

但 verify 方法似乎一直在返回 false。知道为什么会这样。

供应商提供给我的 php 代码中的内容相同

<?php
//load RSA library
include 'Crypt/RSA.php';
//initialize RSA
$rsa = new Crypt_RSA();
//decode & get POST parameters
$payment = base64_decode("VUQxMzE1MTg0OTk0MDM2MzIyMDJ8VDAwMDAxN0kxMFVEMTMxNTE4NDk5NDAzNjMyMjAyfDIwMTctMTAtMDd8MHxwYXltZW50IHN1Y2Nlc3NmdWx8MjAyNTQ=");
$signature = base64_decode("V0T9ZedZW8oB9uy4PazRIxWHvJ7rR+FVtnGjUy30mSKqgmEceZWE1aBvkQWeG4ERjAXHjsRge0D0MlHd9zvXjrLog+G5nWBHIu52O0srCd9d71JVztMQy8fV5oSnRPtlUpgdmn8QDnJ27XrbaHzNxnFyybTQhmbfxkT0oJ0MEOk=");

//load public key for signature matching
$publickey = "-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDSiXzUuH9ePZgSLYrzZ0qhta25
HCb+WG48wIKUl+cQNC/Fl/KZG2cSwRXdo8KZLVWWO5qwzplfTWEylg4IqRA48rYY
f/b+Y7QhORKeAws4pttLZJBbh1mIbZ9HXfQ+zBjP+zfJZ1YjSFs2uZdwSt1itUcJ
/GQFct8GoUevNELG7wIDAQAB
-----END PUBLIC KEY-----";
$rsa->loadKey($publickey);
//verify signature
$signature_status = $rsa->verify($payment, $signature);
//get payment response in segments
//payment format: order_id|order_refference_number|date_time_transaction|payment_gateway_used|status_code|comment;
$responseVariables = explode('|', $payment);       


    //display values
    echo $signature_status;

    echo '<br/>';
    var_dump($responseVariables);


?>  

知道我在这里做错了什么。我尝试在 C# 代码中全部传递“SHA512”、“MD5”,但仍然返回 false。

【问题讨论】:

  • 根据 phpseclib 文档,默认哈希算法是 sha1。你用 C# 试过那个吗?
  • @Michael 是的。这也给出了相同的结果
  • 我想知道您是否还需要(在 PHP 中)$rsa-&gt;setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);。 OAEP 加密是 phpseclib 默认使用的。它比 PKCS1 更安全,但不太常用。
  • @neubert php 实际上来自供应商。我对它没有太多控制权
  • 您确定供应商使用的是CRYPT_RSA_SIGNATURE_PKCS1 而不是CRYPT_RSA_SIGNATURE_PSS

标签: c# php rsa public-key-encryption phpseclib


【解决方案1】:

.NET 4.6+ 支持内置 PSS,但需要使用 RSACng 类(RSACryptoServiceProvider 所基于的 CAPI 不提供它)。

public static bool Verify(byte[] payment, byte[] signature)
{
    var key = Resources.PublicKey;
    // Change the function this calls to return RSACng instead of RSACryptoServiceProvider.
    RSA cipher = Crypto.DecodeX509PublicKey(key);

    // or, failing being able to change it:
    RSA tmp = new RSACng();
    tmp.ImportParameters(cipher.ExportParameters(false));
    cipher = tmp;

    return cipher.VerifyData(
        payment,
        signature,
        HashAlgorithmName.SHA256,
        RSASignaturePadding.Pss);
 }

【讨论】:

  • 什么是 Crypto.DecodeX509PublicKey ?那是从哪里来的?我似乎无法在我的代码中正确引用它。
  • @Ristogod 这是在问题的原始代码中调用的函数。从这个答案的角度来看,它是一个黑匣子。
【解决方案2】:

嗯,供应商似乎没有使用 PKCS1,他使用的是 PSS。以这种方式验证它(需要充气城堡!):

    public static bool Verify(byte[] payment, byte[] signature)
    {
        var pub = @"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDSiXzUuH9ePZgSLYrzZ0qhta25HCb+WG48wIKUl+cQNC/Fl/KZG2cSwRXdo8KZLVWWO5qwzplfTWEylg4IqRA48rYYf/b+Y7QhORKeAws4pttLZJBbh1mIbZ9HXfQ+zBjP+zfJZ1YjSFs2uZdwSt1itUcJ/GQFct8GoUevNELG7wIDAQAB";

        byte[] raw = Convert.FromBase64String(pub);
        AsymmetricKeyParameter aKey = PublicKeyFactory.CreateKey(raw);
        RsaKeyParameters rKey = (RsaKeyParameters)aKey;

        PssSigner pss = new PssSigner(new RsaEngine(), new Sha1Digest(), 20);
        pss.Init(false, rKey);
        pss.BlockUpdate(payment, 0, payment.Length);
        var res = pss.VerifySignature(signature);

        return res;
    }

【讨论】:

  • 是的.. 我猜他们的文档和实现似乎是不同的。非常感谢你的想法。
猜你喜欢
  • 1970-01-01
  • 2011-11-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-22
  • 1970-01-01
  • 2020-10-03
相关资源
最近更新 更多