2

I am using a signing string and a private key to generate a public key using SHA-256 encryption.

The hashing function is a standard C# SHA-256 hashing function:

string CalculateHMAC256(string hmacKey, string signingstring)
    {
        byte[] key = Encoding.UTF8.GetBytes(hmacKey);
        byte[] data = Encoding.UTF8.GetBytes(signingstring);
        using (HMACSHA256 hmac = new HMACSHA256(key))
        {
            byte[] result = hmac.ComputeHash(data);
            return Convert.ToBase64String(result);
        }
    }

The string signature looks like this: allowedMethods:blockedMethods:countryCode:currencyCode:merchantAccount:merchantReference:offset:orderData:paymentAmount:sessionValidity:shipBeforeDate:shopperEmail:shopperLocale:shopperReference:skinCode:::GB:GBP:MyTest:abc:::1:2017-04-28T15:07:10+01:00:2017-04-30::en_US::neDRF4H4

I have also tried this with escaped ':' as advised: allowedMethods:blockedMethods:countryCode:currencyCode:merchantAccount:merchantReference:offset:orderData:paymentAmount:sessionValidity:shipBeforeDate:shopperEmail:shopperLocale:shopperReference:skinCode:::GB:GBP:MyTest:abc:::1:2017-04-29T13:34:48+01:00:2017-05-01::en_US::neDRF4H4

And then my html form looks like this:

 <form ngNoForm name="frmsp" id="frmsp" target="_blank" 
    action="https://test.barclaycardsmartpay.com/hpp/pay.shtml"
    method="post">
    <input type="hidden" name="merchantSig" [value]="merchantSignature" />
    <input type="hidden" name="currencyCode" [value]="smartPayment?.currencyCode" />
    <input type="hidden" name="merchantAccount" [value]="smartPayment?.merchantAccount" />
    <input type="hidden" name="merchantReference" [value]="smartPayment?.merchantReference" />
    <input type="hidden" name="paymentAmount" [value]="smartPayment?.paymentAmount" />
    <input type="hidden" name="sessionValidity" [value]="smartPayment?.sessionValidity" />
    <input type="hidden" name="shipBeforeDate" [value]="smartPayment?.shipBeforeDate" />
    <input type="hidden" name="shopperLocale" [value]="smartPayment?.shopperLocale" />
    <input type="hidden" name="orderData" [value]="smartPayment?.orderData" />
    <input type="hidden" name="skinCode" [value]="smartPayment?.skinCode" />
    <input type="hidden" name="countryCode" [value]="smartPayment?.countryCode" />
    <input type="hidden" name="shopperEmail" [value]="smartPayment?.shopperEmail" />
    <input type="hidden" name="shopperReference" [value]="smartPayment?.shopperReference" />
    <input type="hidden" name="allowedMethods" [value]="smartPayment?.allowedMethods" />
    <input type="hidden" name="blockedMethods" [value]="smartPayment?.blockedMethods" />
    <input type="hidden" name="offset" [value]="smartPayment?.offset" />    
    <input type="submit" value="Process Payment" (click)="buttonClicked()">

Where the fields values are being calculated with angular2 - using the same ones used to build the signing string, so I am confident that the data matches.

When I send the form, I get an error stating that the merchant signature is incorrect.

Perhaps the format of the signing string could be incorrect? I am trying to implement a call to Barclaycard Smartpay using hosted payment. Documentation here: Hosted Payment Page Integration Guide

Note: that the barclays documentation is out of date (last updated 2012) and that the references to SHA-1 are now using SHA-256. It is built using Adyen payment systems and I have reused the string generation examples using the following example code: https://github.com/Adyen/adyen-asp.net-sample-code

trees_are_great
  • 3,881
  • 3
  • 31
  • 62
  • I'm also working on the same thing at the moment :) Did you try the form at the checkhmac page? https://ca-test.adyen.com/ca/ca/skin/checkhmac.shtml – ThdK Apr 28 '17 at 11:34
  • Super, hopefully we can solve this together. I did. I am able to get it working by generating the signature on that page and then creating a html form similar to the one above to match those values in the test page. The problem comes that I can never get a merchant signature to match the one generated on that page. (I am actually using the barclays smartpay test page, which I imagine is basically identical to the page you are talking about). – trees_are_great Apr 28 '17 at 12:26
  • Did you compare your signingstring with the signingstring generated on the test page? I see your signing string contrains ":" that should be replaced with "\:" – ThdK Apr 28 '17 at 12:32
  • I've tried the following signing string: allowedMethods\:blockedMethods\:countryCode\:currencyCode\:merchantAccount\:merchantReference\:offset\:orderData\:paymentAmount\:sessionValidity\:shipBeforeDate\:shopperEmail\:shopperLocale\:shopperReference\:skinCode\:\:\:GB\:GBP\:MyTest\:abc\:\:\:1\:2017-04-29T13\:34\:48+01\:00\:2017-05-01\:\:en_US\:\:neDRF4H4 Do i need to escape the date in the html form? I have tried using the signing string from the test page and then getting the signature using that signing string, but that gives me an incorrect SHA-256 encryption. – trees_are_great Apr 28 '17 at 12:41
  • You only need to replace the ":" in your values! the ":" is used as a seperator. – ThdK Apr 28 '17 at 12:47
  • Also the SHA-256 encryption that you are using gives a wrong result for me. Try using the function from the sample code on this page: https://github.com/Adyen/adyen-asp.net-sample-code/blob/master/AdyenExamples/1.HPP/CreatePaymentOnHpp256.cshtml – ThdK Apr 28 '17 at 12:48

1 Answers1

4

There is a problem with your signing string. You need to replace "\" with "\" and ":" with ":" in all your vallues.

I also suggest to use the code from this sample on GIT to generate create your encrypted signature.

Using the code below I get the same signature as on the test page provided by Adyen.

 // Computes the Base64 encoded signature using the HMAC algorithm with the HMACSHA256 hashing function.
    string CalculateHMAC(string hmacKey, string signingstring)
{
    byte[] key = PackH(hmacKey);
    byte[] data = Encoding.UTF8.GetBytes(signingstring);

    try
    {
        using (HMACSHA256 hmac = new HMACSHA256(key))
        {
            // Compute the hmac on input data bytes
            byte[] rawHmac = hmac.ComputeHash(data);

            // Base64-encode the hmac
            return Convert.ToBase64String(rawHmac);
        }
    }
    catch (Exception e)
    {
        throw new Exception("Failed to generate HMAC : " + e.Message);
    }
}

byte[] PackH(string hex)
{
    if ((hex.Length % 2) == 1)
    {
        hex += '0';
    }

    byte[] bytes = new byte[hex.Length / 2];
    for (int i = 0; i < hex.Length; i += 2)
    {
        bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
    }

    return bytes;
}

Try to use only a limited amound of fields and see if you get any results. I used the fields below (also take their order into account!)

currencyCode:merchantAccount:merchantReference:paymentAmount:sessionValidity:shipBeforeDate:shopperLocale:skinCode
DGibbs
  • 14,316
  • 7
  • 44
  • 83
ThdK
  • 9,916
  • 23
  • 74
  • 101
  • You are my hero. Thanks ThdK! I had been stuck on this for so long. I actually had the other method in my code, but it didn't work when my string wasn't correctly escaped. Perhaps you could also mention the escaping in the answer. – trees_are_great Apr 28 '17 at 12:53