0

I am trying to decrypt and validate the hash but at times of decrypting, it throws me the error 'Key does not exist' and at the time of validating the hash return False

https://payvyne.readme.io/docs/webhooks

Signature:

HEjoCsghC9X0slrE2DprptDLYdoA7jaw4Jl7vpJVxzx9GNJEiO3pYGLDPhLmVqk98QJJ/FuiS5J+fvp+msr3Y8aFzKqjRQXj5TBELT38N+A7I8y3Vc0mgeR0aDMx7I83yhfkcoyhdiGJibzqQ5SYFZ0nnEVHYXheLUlga45yg/McDICtMm6lhnrPWEuHzoZTQkhsrLN/1W1PtLjJ2DickWB78PmhpeflL2Cpe6qS3qCclqFGZ7HIl9OoxU4WXpTYgxw7eixAKB7apFdFqea4BnGravfENNl97pOBuU6fRof4KtMczVagQw3QnxFD3BBtpTepRaT+jHY8wStXUG1bxllH32WiA9CVcpY4mxKhpxzQ8YD0b+3OgkpzZYS+BVVAdVazMJeEAw7v/zaxpjbR+Zo5l9vOLdyatwM75qpwMoKnMeKJHeRytEOK54al49OHiaE+v1OkOhJA0zh5nLzEIZanIdf+hXHDz3Euecs/p0cABiFNmhzYY5fl8qEytK6j2CjXQOYgljG5dqPm7M9CW36ntZTDaIEVWql3jdi9frxc4/82w1jhROFL0pBG1zz8nimAEesB1AaxmNqW7BIxULweX7eaReeo/dIqDSbmFuT+TikPQo4XRtmpDqO37Y9P6q7ZXtHOFopSaykHUHs+NgrKlBJMM5ADg5bHWm2Qows=

Public key:

pA6ULfXWrIMq-qvxn_0CykoStq0ZMYm63lHsuXTsE4q4tgekLJDW2Lnf35ilbFU_vybBdyeJAphpsYc4P0eJBt_z2T62HAV3gnwp_GU6hWIo8faK31TSXIrLmGjZlAVynAxjFYZoNxMeZuwEXpxG4bRGs58P7XSx1fAzedX6oGIlcSLljKH4I1BHt6gJhPIHYNXQzq_a0hX54C1m1VDVP_kot8ui1YKZil_riROK_Xk4ktnOTAqXo9z4uNBqzzH2k0J2YNiCb8VOdbp7kjmH9sPLI-jb-ociy0wSkGZc1e8saGIkkSm4eUASvX_M_TTDD99OrgoIS2Vx07Tw4lK5yd28EMVBUzy2OypuPVf9PyoDGv_4241x5PpJsA9IKocD7AgwxJ3E7FBFhvuSP8c5wspkbQxBwv5nnk2zAxuZsiJeK0o3JSxjkZJEkeVY4mA3VV9SvSXEKAFg2h9J3CR9PTwrZoVBruycVtWJ4it5jroXff-aGlLoRAO0g3gtfjkJb3tw6SJTFOA49iJci76Mj8Adz3eeEEGxTxfDzh_lq0jXxTk7cQSaR2_ChYLHaoorrrFmAvWgDH_lSvlISIgey-SzUoJM9RAy4gVFdmg-XCQQlpMh_d1-IACO3EfBvYKWE-6uGIqx1nZhn9WIDdSqMp6940xRxl0vQy8vYCQ5q8U

Data for Sign in string:

{"type":"PAYMENT_STATUS_CHANGE","paymentId":"1c6e834f074ec941","status":"FAILED","timestamp":1652688286662,"amount":"164.69","currency":"GBP","description":"This is test payment","paymentType":"ONE_OFF","bankName":"Diamond bank","destinationAccount":"GBP2","createdAt":"2022-05-16T08:04:32.994","updatedAt":"2022-05-16T08:04:46.662","customerReference":"1199","refundedAmount":"0.00"}

Expo (exponent):

AQAB

Below is the code to Decrypt the signature using public key.

public static void DecryptUsingPublicKey(string publicKey, string expo, string signature)
{
    var modulus = ConvertToBase64(publicKey);
    var exponent = Convert.FromBase64String(expo);

    RSACryptoServiceProvider csp = new RSACryptoServiceProvider(2048);
    var _publicKey = csp.ExportParameters(false);

    _publicKey.Modulus = modulus;
    _publicKey.Exponent = exponent;
    csp.ImportParameters(_publicKey);

    var dataBytes = ConvertToBase64(signature);
    var plainText = csp.Decrypt(dataBytes, false);
    var returnData = Encoding.Unicode.GetString(plainText);
    Console.WriteLine($"value: {returnData}");
}

Below is the code for Verify signature using public key

public static void VerifySignature(string signature, string pKey, string dataForSign)
{
    string pKeyNew = pKey;
    pKeyNew = pKeyNew.Replace("_", "/").Replace("-", "+");
    string publicKey = $"<RSAKeyValue><Modulus>{pKeyNew}==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";

    var encoder = new UTF8Encoding();
    byte[] dataForSignAsBytes = encoder.GetBytes(dataForSign);

    byte[] signatureAsBytes = ConvertToBase64(signature);

    RSACryptoServiceProvider rsaCryptoServiceProvider = new RSACryptoServiceProvider();
    rsaCryptoServiceProvider.FromXmlString(publicKey);

    var hashData = SHA256.Create().ComputeHash(dataForSignAsBytes);

    var result1 = rsaCryptoServiceProvider.VerifyData(dataForSignAsBytes, CryptoConfig.MapNameToOID("SHA256"), signatureAsBytes);
    var result2 = rsaCryptoServiceProvider.VerifyHash(hashData, CryptoConfig.MapNameToOID("SHA256"), signatureAsBytes);
    var result3 = rsaCryptoServiceProvider.VerifyHash(hashData, signatureAsBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
    var result4 = rsaCryptoServiceProvider.VerifyData(dataForSignAsBytes, signatureAsBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
    Console.WriteLine(result1);
    Console.WriteLine(result2);
    Console.WriteLine(result3);
    Console.WriteLine(result4);
}

ConvertToBase64 function

public static byte[] ConvertToBase64(string data)
{
    byte[] cyperBuffer;
    string dataNew = data;
    dataNew = dataNew.Replace("_", "/").Replace("-", "+");
    try
    {
        if (dataNew.Substring(dataNew.Length - 1) != "=")
        {
            dataNew += "=";
        }
        cyperBuffer = Convert.FromBase64String(dataNew);
    }
    catch
    {
        dataNew += "=";

        try
        {
            cyperBuffer = Convert.FromBase64String(dataNew);
        }
        catch
        {
            //If any error occured while convert to base64 then append '=' at the end.
            dataNew += "=";
            cyperBuffer = Convert.FromBase64String(dataNew);
        }
    }

    return cyperBuffer;
}
sabir
  • 1
  • 1
  • 2
  • For decryption, the private key is required. – Topaco May 16 '22 at 14:35
  • 1
    Regarding verification: There is a bug in `publicKey`. `pKey` is Base64url decoded 512 bytes large. Thus, Base64 encoded it must not be padded with *two* padding bytes, but only *one*. Btw, instead of the static `==`, a more generic solution makes more sense, e.g. from [here](https://stackoverflow.com/a/26354677/9014097). If this is fixed and - as already identified in the answer - the signature is Base64 decoded with `Convert.FromBase64String(signature)`, verification with all four variants is successful. – Topaco May 16 '22 at 15:58
  • I strongly suspect a copy paste error for the `publicKey`, but OK, make that 2 conversion errors :P Note that I think the whole idea of outputting bytes for base 64 *encoding* is a mistake in itself; just outputing characters or a text string makes much more sense (even though the standard often describes it as a byte-to-byte/ASCII encoding as well). – Maarten Bodewes May 16 '22 at 19:26
  • Hi @Topaco, We are getting the public key in JSON Web Algorithms like, https://datatracker.ietf.org/doc/html/rfc7518#section-6.3.1.1. – sabir May 17 '22 at 06:35
  • With your implementation of `ConvertToBase64()` the verification is successful if you replace `{pKeyNew}==` with `{pKeyNew}=`! Regarding `ConvertToBase64()`: The name is poor, because in the end a Base64url/Base64 decoding takes place (exactly the opposite of what the name suggests). The equally poor implementation works for your key, but not in general. My recommendation: For the conversion of the key from Base64url to Base64 use: https://stackoverflow.com/a/26354677/9014097 and Base64 decode the signature with `Convert.FromBase64String(signature)`. – Topaco May 17 '22 at 08:05
  • S. online on .NET Fiddle: https://dotnetfiddle.net/TEDBHY. – Topaco May 17 '22 at 08:06
  • Hey @Topaco, Thanks for the help in verifying the signature but I still faced the issue in decrypt the signature. Please let me know if you may have an idea. it throws the error **Key does not exist** – sabir May 17 '22 at 09:33
  • I' ve posted an executable code on .NET Fiddle. Just compare your code. – Topaco May 17 '22 at 09:38

1 Answers1

0

This is a conversion mistake; you need to decode the base 64 signature, not encode the signature, so the following line is wrong:

byte[] signatureAsBytes = ConvertToBase64(signature);

it should be something like:

byte[] signatureAsBytes = ConvertFromBase64(signature);

Decryption is modular exponentiation with a private key. Furthermore, encryption normally uses a different padding scheme than signature generation, so you'd expect that the unpadding would fail if you try and decrypt. Only verification is possible.

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
  • Hi, Thank you for your suggestion, I forgot to put my ConvertToBase64 function. – sabir May 17 '22 at 06:13
  • That's a rather generic function for base64url decoding, please don't code that yourself. Try again with one provided by a library, or at least write some unit tests. How performant do *you* think those replacement statements are? And you only seem to add *one* `=` character at max. They should be added until the base 64 characters are a multiple of 4 - that's why padding characters exist. – Maarten Bodewes May 17 '22 at 20:12