0

I am trying to do an HMAC-SHA256 signature calculation in apex , but couldn't find clear instructions from the service provider on how to generate a request string for creating an HMAC-Signature.

But found below rails code on the vendor site showing how to generate the request string.

Can someone with rails hands on can help on showing how the exact output of below variables will look like

sorted_key_values request_string

By seeing the proper output of these I can analyze on how to implement the same in the apex. Sample service request payload:

{
  "to_account":"Example user",
  "token":"5TH3ACC3AU21",
  "transaction_reference":"",
  "from_account":"First1 Last1",
  "from_fund":"THE TORONTO-DOMINION BANK",
  "transaction_type":"send_money",
  "amount_in_cents":500,
  "type":"transaction",
  "created_by_user":"699cMPe6BAyqvVsZA5mo",
  "message":"",
  "state":"completed",
  "link_url":"",
  "email":"[email protected]",
  "signature":"USYpBfZFQQHa2%2BT6UtDPUVFfUPP0aobWpXe5DE9hPOY%3D%0A"
}

Sample HMAC-SHA256 signature calculation - using Rails/Sinatra code

require 'openssl'
require 'base64'
require 'erb'

webhook_url = 'http://your.domain.com/your/webhook/url';
webhook_signing_key = 'v7aJHjbbxASKiwDW5wq6';

original_signature = params.delete(:signature)
sorted_key_values = params.keys.sort.map{ |key| "#{key}#{params[key]}" }.join

// looking to see how the output of sorted_key_values variable will look like

request_string = "POST\n#{webhook_url}\n#{sorted_key_values}"

// looking to see how the final output of request_string variable will look like

1 Answer 1

1

Based on the code, it looks like you'd have something like the following:

Map<String, Object> params = 
    (Map<String, Object>)JSON.deserializeUntyped(
    '{  "to_account":"Example user",  "token":"5TH3ACC3AU21",  "transaction_reference":"",  "from_account":"First1 Last1",  "from_fund":"THE TORONTO-DOMINION BANK",  "transaction_type":"send_money",  "amount_in_cents":500,  "type":"transaction",  "created_by_user":"699cMPe6BAyqvVsZA5mo",  "message":"",  "state":"completed",  "link_url":"",  "email":"[email protected]",  "signature":"USYpBfZFQQHa2%2BT6UtDPUVFfUPP0aobWpXe5DE9hPOY%3D%0A"}'
    );
Set<String> keySet = params.keySet().clone();
keySet.remove('signature');
String[] keys = new List<String>(keySet), parts = new String[0];

keys.sort();
String unsignedString, privateKey = 'v7aJHjbbxASKiwDW5wq6', webhookUrl='http://your.domain.com/your/webhook/url', method='POST';
for(String key: keys) {
    parts.add(key+params.get(key));
}
unsignedString = String.join(parts, '');
String signature = EncodingUtil.urlEncode(
    EncodingUtil.base64Encode(
        Crypto.generateMac('hmacSHA256', 
           Blob.valueOf(method+'\n'+webhookUrl+'\n'+unsignedString), 
           EncodingUtil.base64Decode(privateKey))
    )+'\n',
    'utf-8'
);
System.assertEquals(params.get('signature'), signature);

Unfortunately, it's not a perfect match, as I'm getting the following error:

System.AssertException: Assertion Failed: Expected: USYpBfZFQQHa2%2BT6UtDPUVFfUPP0aobWpXe5DE9hPOY%3D%0A, Actual: %2FeZKfRt%2FQaSA8mltwwGaM36pOC2WqO7pjuSInjwxSmc%3D%0A

I feel like it's close, but perhaps the example data was not perfectly correct, or perhaps I've misunderstood the fragments you've presented in your question. However, I hope that this gets you close enough to get the rest of the way.

1
  • thanks, Biran :) , even the system assert fails I guess your approach is perfect.As this is a sample code snippet I have posted the values might not be correct. I will try with real data and update you back.
    – Rajasekhar
    Commented Jun 7, 2017 at 16:16

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .