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:
- Sorting the headers (except the Signature header) and removing extra spaces around the fields.
- Concatenating the headers using a delimiter &.
- ASCII encoding the SecretKey.
- UTF8 encoding the concatenated header string.
- 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.
- //sortvar dict = requestHeaderDictionary.OrderBy(t => t.Key).ToList();
- //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 - var encoding = new ASCIIEncoding();byte[] secretKeyBytes = encoding.GetBytes(secret);
The secret is i4pu7k3y secretKeyBytes.Length is 8 - byte[] signature = Encoding.UTF8.GetBytes(concatenatedString); signature.Length is 211
- 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
Updated 30 days ago