HMAC calculation

The HMAC calculation for MasterPass transactions differ a bit from the standard HMAC calculation. 

Description

The MAC secures the key-value pairs which is considered part of the secured message. A key-value pair having a key which is either prefixed by "s_" or appears on the list of keys recognised by DIBS is considered a part of the secured message, and all other key-value pairs are ignored in the calculation. The key-value pairs in the secured message must be sorted by the key in ASCII-order with upper and lower case letters grouped seperately. The key and value must be separated by a "=", and each key-value pair should be separated by a "&".
The following example illustrates above rules:

If the following JSON string is used in the call to DIBS:

{
  "merchantId":"90058096",
  "acceptableCards":"master,amex,diners,discover,maestro,visa,cup,jcb",
  "cartContent":[{
    "Description":"OrderItem1-Description",
    "Quantity":1,
    "Value":51,
    "ImageURL":"OrderItem1-ImageURL"
  },{
    "Description":"OrderItem2-Description",
    "Quantity":2,
    "Value":5,
    "ImageURL":"OrderItem2-ImageURL"
  }],
  "currencyCode":"DKK",
  "shippingLocationProfile":"default",
  "suppressShippingAddress":false,
  "test":true,
  "MAC":"9da32a1f6ce93819f6626bd0be16ee4e7f4eb7a0cbedef6beb14d674b2f7a15b"
}

The message used for the calculation should be:

Description=OrderItem1-Description&Description=OrderItem2-Description&ImageURL=OrderItem1-ImageURL&ImageURL=OrderItem2-ImageURL&Quantity=1&Quantity=2&Value=5&Value=51&acceptableCards=master,amex,diners,discover,maestro,visa,cup,jcb&currencyCode=DKK&merchantId=90058096&shippingLocationProfile=default&suppressShippingAddress=false&test=true

Please note – the array's name (“cartContent”-in this example) is ignored where only the content of it is added to the MAC-string. Furthermore it should be noticed that upper case keys comes before lower case keys, e.g. "Quantity" before "acceptableCards", and that integers (such as the "Value" parameter), should be sorted as if it was a string (so e.g. 10 before 9).

The MAC is calculated using the HMAC algorithm with SHA-256. The HMAC algorithm requires a message and one key. The message is the above message and the key is the merchant specific key found in the DIBS Administration:

DIBS Administration / Preferences / HMAC key

Calculation method

The HMAC calculation is done using the secret key found in the DIBS Admin. The calculation should be done as following:

MAC = HMAC-SHA256(hexDecode(K),M)

where K denotes the shop specific key found in the DIBS Administration and M is the previously mentioned message.

Example

If we use the previously found message:

M = "Description=OrderItem1-Description&Description=OrderItem2-Description&ImageURL=OrderItem1-ImageURL&ImageURL=OrderItem2-ImageURL&Quantity=1&Quantity=2&Value=5&Value=51&acceptableCards=master,amex,diners,discover,maestro,visa,cup,jcb&‌currencyCode=DKK&merchantId=90058096&shippingLocationProfile=default&suppressShippingAddress=false&test=true"
K = "3479683f37725e2e33416a45782a69286972245a656e595d4f797a4c5a57393925672b2d584f306f2431374f4c74387448356b502d57323f785e6a434c293f46"
MAC = HMAC-SHA256(hexDecode(K), M) = 9da32a1f6ce93819f6626bd0be16ee4e7f4eb7a0cbedef6beb14d674b2f7a15b

HMAC calculation functions

/**
* calculateMac
* Calculates the MAC key from a set of parameters and a secret key
* @param array msg Message array in key => value format
* @param string k Secret HMAC key from DIBS Admin
* @return string
*/
function calculateMac(msg, k) {
    //Decode the hex encoded key
    k = pack('H*', k);
    
    //Sort the key=>value array ASCII-betically according to the key
    ksort(msg, SORT_STRING);
    
    //Create message from sorted array.
    msg = urldecode(http_build_query(msg));
    
    //Calculate and return the SHA-256 HMAC using algorithm for 1 key
    return hash_hmac("sha256", msg, k);
}
using System;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.IO;
using Newtonsoft.Json;
using System.Globalization;
using System.Security.Cryptography;
/**
* calculateMac
* Calculates the MAC key from the post parameters and a secret key
* @param params String containing the sorted post parameters
* @param K_hexEnc String containing the hex encoded secret key from DIBS Admin
* @return String containing the hex encoded MAC key calculated
**/
static string calculateMac(string params, string K_hexEnc) {

  //Decoding the secret Hex encoded key and getting the bytes for MAC calculation
  var K_bytes = new byte[K_hexEnc.Length / 2];
  for (int i = 0; i < K_bytes.Length; i++) {
    K_bytes[i] = byte.Parse(K_hexEnc.Substring(i * 2, 2), NumberStyles.HexNumber);
  }

  //Getting bytes from message
  var encoding = new ASCIIEncoding();
  byte[] param_bytes = encoding.GetBytes(params);

  //Calculate MAC key
  var hash = new HMACSHA256(K_bytes);
  byte [] mac_bytes = hash.ComputeHash(param_bytes);
  string mac = BitConverter.ToString(mac_bytes).Replace("-", "").ToLower();

  return mac;
}
/**
 * Dependencies:
 * Apache-Commons/Commons-Codec for Hex encoding/decoding
 * Codehaus/Jackson for JSON mapping
 */
/**
 * calculateMac Calculates the MAC from a given Map holding the post parameters and the secret key from DIBS Admin
 *
 * @param parameters String holding all post parameters which are already sorted
 * @param macKeyHex  Hex encoded secret key from DIBS Admin
 * @return The MAC string calculated from the message and secret key using the hmac-sha256 algorithm
 */
public String calculateMac(String parameters, String macKeyHex) {
    try {
        // Decode the hex-encoded secret key
        byte[] macKey = Hex.decodeHex(macKeyHex.toCharArray());

        // Calculate the hmac from message and secret key
        Mac hmacSha256 = Mac.getInstance("HmacSHA256");
        hmacSha256.init(new SecretKeySpec(macKey, "HmacSHA256"));
        byte[] mac = hmacSha256.doFinal(parameters.getBytes(Charset.forName("UTF-8")));

        // Return the hex-encoded hmac
        return Hex.encodeHexString(mac);
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (InvalidKeyException e) {
        e.printStackTrace();
    } catch (DecoderException e) {
        e.printStackTrace();
    }
    return null;
}
Do you have question or need help?
Follow us
DIBS Payment Services
Stockholm +46 (0)8-527 525 00
Göteborg +46 031-600 800
København +45 7020 3077
Oslo +47 21 55 44 00