Construct Messages Using HTTP Signature Security

HTTP signatures use a digital signature to enable the receiver to validate the sender's authenticity and ensure that the message was not tampered with during transit. For more information about HTTP signatures, see the IETF Draft that is maintained by the IETF HTTP Working Group (https://httpwg.org).
Follow these steps to implement HTTP signatures:
  1. Create the shared secret key pair. See Create a Shared Secret Key Pair.
  2. Generate a hash of the message body. See Generate a Hash of the Message Body.
  3. Generate a signature hash. See Generate the Signature Hash.
  4. Populate the
    signature
    header field. See Update Header Fields.

Elements of an HTTP Message

A HTTP Message is built with the following elements:

Headers

Your message header must include these header fields:
HTTP Header Fields
HTTP Header Field
Description
v-c-merchant-id
Your
Cybersource
organization ID.
Date
The date of the transaction in the RFC1123 format. (Thu, 18 Jul 2019 00:18:03 GMT)
Content-Type
Also known as the Multipurpose Internet Mail Extension (MIME) type, this identifies the media or file type of the resource. (application/json)
Host
The transaction endpoint. (
https://api.cybersource.com
)

Body

The message body. For more information on setting up the body, see Generate a Hash of the Message Body.

Generate a Hash of the Message Body

This hash is used to validate the integrity of the message at the receiving end.
Follow these steps to generate the hash:
  1. Generate the SHA-256 hash of the JSON payload (body of the message).
  2. Encode the hashed string to Base64.
  3. Prepend
    SHA-256=
    to the front of the hash.
  4. Add the message body hash to the
    digest
    header field.
Creating a Message Hash Using the Command Line
shasum
Tool
        
echo -n "{"clientReferenceInformation":{"code":"TC50171_3"},"paymentInformation":{"card":{"number": "4111111111111111","expirationMonth":"12","expirationYear":"2031"}},"orderInformation":{"amountDetails": {"totalAmount":"102.21","currency":"USD"},"billTo”:{“firstName":"John","lastName":"Doe","address1": "1MarketSt","locality":"sanfrancisco","administrativeArea":"CA","postalCode":"94105","country":"US", "email":"
test@cybs.com
","phoneNumber":"4158880000"}}}" | shasum -a 256
        
echo -n "6ae5459bc8a7d6a4b203e8a734d6a616725134088e13261f5bbcefc1424fc956" | base64
Creating a Message Hash Using the Command Line
base64
Tool
        
echo -n "6ae5459bc8a7d6a4b203e8a734d6a616725134088e13261f5bbcefc1424fc956" | base64
Creating a Message Hash Using C#
        
public static string GenerateDigest() { var digest = ""; var bodyText = "{ your JSON payload }"; using (var sha256hash = SHA256.Create()) { byte[] payloadBytes = sha256hash .ComputeHash(Encoding.UTF8.GetBytes(bodyText)); digest = Convert.ToBase64String(payloadBytes); digest = "SHA-256=" + digest; } return digest; }
Creating a Message Using Java
        
public static String GenerateDigest() throws NoSuchAlgorithmException { String bodyText = "{ your JSON payload }"; MessageDigest md = MessageDigest.getInstance("SHA-256"); md.update(bodyText.getBytes(StandardCharsets.UTF_8)); byte[] digest = md.digest(); return "SHA-256=" + Base64.getEncoder().encodeToString(digest); }
Digest Header Field
    
digest: SHA-256=NmFlNTQ1OWJjOGE3ZDZhNGIyMDNlOGE3MzRkNmE2MTY3MjUxMzQwODhlMTMyNjFmNWJiY2VmYzE0MjRmYzk1Ng==

Generate the Signature Hash

The signature hash is a Base64-encoded HMAC SHA-256 hash of the header fields and their values. The following information must be included in the signature hash:
Header Fields
Header Field
Description
Date
From the header, the date and time in the RFC1123 format.
For example:
Date: Thu, 18 Jul 2023, 22:18:03.
Digest
The Base64-encoded SHA-256 hash of the message body. For more information, see Generate a Hash of the Message Body.
For example:
Digest: SHA-256=gXWufV4Zc7VkN9Wkv9jh/JuAVclqDusx3vkyo3uJFWU=
.
Do not include the digest with GET requests.
Host
From the header, the endpoint host.
For example:
apitest.cybersource.com
.
v-c-merchant-id
From the header, the merchant ID associated with the request.
For example:
v-c-merchant-id: mymerchantid
.
request-target
The HTTP method and endpoint resource path.
For example:
request-target: post /pts/v2/payments/
.
Follow these steps to generate the signature hash value:
  1. Generate a byte array of the secret key generated previously. For more information, see Create a Shared Secret Key Pair.
  2. Generate the HMAC SHA-256 key object using the byte array of the secret key.
  3. Concatenate a string of the required information listed above.
    For more information, see
    Creating the Validation String
    below.
  4. Generate a byte array of the validation string.
  5. Use the HMAC SHA-256 key object to create the HMAC SHA-256 hash of the validation string byte array.
  6. Base64 encode the HMAC SHA-256 hash.
Signature Hash
    
signature=”OuKeDxj+Mg2Bh9cBnZ/25IXJs5n+qj93FvPKYpnqtTE=”

Creating the Validation String

To create the validation string, concatenate the required information in the same order as listed in the signature header field parameter. Each item must be on a separate line, and each line should be terminated with a new line character
\n
.
Validation String Example
    
host:
apitest.cybersource.com
\n date: Thu, 18 Jul 2019 00:18:03 GMT\n request-target: post /pts/v2/payments/\n digest: SHA-256=gXWufV4Zc7VkN9Wkv9jh/JuAVclqDusx3vkyo3uJFWU=\n v-c-merchant-id: mymerchantid
Generating a Signature Hash in C#
    
private static string GenerateSignatureFromParams(string signatureParams, string secretKey) { var sigBytes = Encoding.UTF8.GetBytes(signatureParams); var decodedSecret = Convert.FromBase64String(secretKey); var hmacSha256 = new HMACSHA256(decodedSecret); var messageHash = hmacSha256.ComputeHash(sigBytes); return Convert.ToBase64String(messageHash); }
Generating a Signature Hash in Java
    
public static String GenerateSijava.io.PrintWriter@6eba506b gnatureFromParams(String keyString, String signatureParams) throws InvalidKeyException, NoSuchAlgorithmException { byte[] decodedKey = Base64.getDecoder().decode(keyString); SecretKey originalKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, "HmacSHA256"); Mac hmacSha256 = Mac.getInstance("HmacSHA256"); hmacSha256.init(originalKey); hmacSha256.update(signatureParams.getBytes()); byte[] HmachSha256DigestBytes = hmacSha256.doFinal(); return Base64.getEncoder().encodeToString(HmachSha256DigestBytes);}

Update Header Fields

When the signature is generated, you can populate the
signature
header field. The
signature
header field includes these parameters:
Signatures
Signature Parameter
Description
kid
The shared secret key used to encrypt the signature.
algorithm
The HMAC SHA256 algorithm used to encrypt the signature. It should be formatted:
HmacSHA256
.
headers
This ordered list of the fields included in the signature:
  • host
  • date
  • request-target
  • digest
  • v-c-merchant-id
signature
The signature hash.

Signature Header Field Format

Signature:"keyid:"[shared secret key]",algorithm="[encryption algoritm]",headers="field1" "field2" "field3" "etc.", signature="[signature hash]"

Signature Header Example

      
Signature:"kid="123abcki-key1-key2-key3-keyid1234567", algorithm="HmacSHA256", headers="host date request-target digest v-c-merchant-id", signature="hrptKYTtn/VfwAdUqkrQ0HT7jqAbagAbFC6nRGXrNzE="