Digital Signatures

How the Digital Signature Works

Calculating the Signature

Green Dot issues each partner a secret key used to calculate the digital signature. Calculating each key involves the following steps:

  1. Sorting the headers (except the Signature header) and removing extra spaces around the fields.
  2. Concatenating the headers using a delimiter &.
  3. ASCII encoding the SecretKey.
  4. UTF8 encoding the concatenated header string.
  5. Hashing the string using SHA-256 (use the key as SecretKey). Secret Key is shared between Green Dot and the partner.

Coding Used

Green Dot uses the following C# code to generate the signature.

//sort
var dict = requestHeaderDictionary.OrderBy(t => t.Key).ToList();
//concatenate
var pairs = dict.Where(p => (p.Key != “x-gdn-signature”) && (!string.IsNullOrWhiteSpace(p.Value))).Select(x => string.Format("{0}{1}{2}", x.Key, ":", x.Value));var 
concatnatedString = string.Join("&", pairs).ToLower();
var encoding = new ASCIIEncoding();
byte\[] secretKeyBytes = encoding.GetBytes(secret);
byte\[] signature = Encoding.UTF8.GetBytes(concatnatedString);using (var hmac = new HMACSHA256(secretKeyBytes))
{          
  byte\[] signatureBytes = hmac.ComputeHash(signature);        
  return string.Concat(signatureBytes.Select(b => b.ToString("X2")).ToArray());
}

📘

Before performing the concatenation/hashing, make sure all characters are converted to lower case and the strings are trimmed (left/right) for the extra white spaces. Do not include headers that have null/empty values.

Sample Procedures

Following are the steps to generate the digital signature. You may check the results of each step.

  1. //sortvar dict = requestHeaderDictionary.OrderBy(t => t.Key).ToList();
  2. //concatenatevar pairs = dict.Where(p => (p.Key != WebApiRequestHeaders.X_GDN_Signature) && (!string.IsNullOrWhiteSpace(p.Value))).Select(x => string.Format("{0}{1}{2}", x.Key, ":", x.Value));var concatenatedString = string.Join("&", pairs).ToLower();
    The is x-gdn-channeltype:1&x-gdn-devicetype:2&x-gdn-encryptiontype:1&x- gdn-ipaddress:192.168.1.1&x-gdn-messageid:61aa6e58-b442-4839-8432- 948af2fad3c5&x-gdn-programnumber:bahu-bc2019&x-gdn-timestamp:2020-05- 22t03:07:53z
  3. var encoding = new ASCIIEncoding();byte[] secretKeyBytes = encoding.GetBytes(secret);
    The secret is i4pu7k3y secretKeyBytes.Length is 8
  4. byte[] signature = Encoding.UTF8.GetBytes(concatenatedString); signature.Length is 211
  5. using (var hmac = new HMACSHA256(secretKeyBytes))
    {
    byte[] signatureBytes = hmac.ComputeHash(signature);
    return string.Concat(signatureBytes.Select(b =>b.ToString("X2")).ToArray());
    }
    signatureBytes.Length is 32
    The x-gdn-signature is
    0116eb70450b743f26ccc701f598341f3e6d5b04d50979897571125928d65e8d

Invalid X_GDN  Signature Error

<base_response xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://greendotcorp.com/WebServices/Corporate/GDFNReloadServices/">
<gd_response_code>351000019</gd_response_code>
<gd_response_date>2020-05-27T07:32:57.0244211Z</gd_response_date>
<gd_response_message>Invalid X_GDN_Signature</gd_response_message>
<gd_transaction_reference>3b938107-cef0-4515-8e0f- efca6e45d656</gd_transaction_reference>
<partner_transaction_reference i:nil="true" />
</base_response>

Sample Input and Resulting Signature

Sample Header Input

{
      "x-gdn-timestamp": "2020-05-22T03:07:53Z",
      "x-gdn-encryptiontype": "1",
      "x-gdn-messageid": "61aa6e58-b442-4839-8432-948af2fad3c5",    
      "x-gdn-channeltype": "1",    
      "x-gdn-devicetype": "2",   
     "x-gdn-ipaddress": "192.168.1.1",    
      "x-gdn-programnumber": "Bahu-BC2019"
}

Sample Body Input

{
"gd_retailer_key”: "2433",
"amount”: "22.22"
}

Sample Concatendated Values

“x-gdn-channeltype:1&x-gdn-devicetype:2&x-gdn-encryptiontype:1&x-gdn-ipaddress:192.168.1.1&x-gdn-messageid:61aa6e58-b442-4839-8432-948af2fad3c5&x-gdn-programnumber:bahu-bc2019&x-gdn-timestamp:2020-05-22t03:07:53z”

Resulting Signature

Using the sample secret key i4pu7k3y, the resulting hash/signature would be as follows:

0116eb70450b743f26ccc701f598341f3e6d5b04d50979897571125928d65e8d