Aneef
Aneef

Reputation: 3729

rsacryptoserviceprovider.VerifyData always returns false

Below is my C# Program that verifies a response from a php script which is using phpseclib

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;
        }

the public key used is below:

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

but the verify method seems to be returning false all the time. any idea why this happens.

the same content works in the php code which the vendor gave to me

<?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);


?>  

Any idea what i'm doing wrong here. i tried passing "SHA512", "MD5" all in the C# code and still returns false.

Upvotes: 1

Views: 3880

Answers (2)

bartonjs
bartonjs

Reputation: 33108

PSS is supported in-the-box with .NET 4.6+, but requires using the RSACng class (CAPI, which RSACryptoServiceProvider is based on, doesn't offer it).

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);
 }

Upvotes: 3

Michael
Michael

Reputation: 2123

Well, seems like the vendor is NOT using PKCS1, he's using PSS. Verify it this way (requires Bouncy Castle!):

    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;
    }

Upvotes: 2

Related Questions