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:
- Create the shared secret key pair. See Create a Shared Secret Key Pair.
- Generate a hash of the message body. See Generate a Hash of the Message Body.
- Generate a signature hash. See Generate the Signature Hash.
- Populate thesignatureheader 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 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:
- Generate the SHA-256 hash of the JSON payload (body of the message).
- Encode the hashed string to Base64.
- PrependSHA-256=to the front of the hash.
- Add the message body hash to thedigestheader field.
Creating a Message Hash Using the Command Line
shasum
Toolecho -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":"","phoneNumber":"4158880000"}}}" | shasum -a 256
echo -n "6ae5459bc8a7d6a4b203e8a734d6a616725134088e13261f5bbcefc1424fc956" | base64
Creating a Message Hash Using the Command Line
base64
Toolecho -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 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:
- Generate a byte array of the secret key generated previously. For more information, see Create a Shared Secret Key Pair.
- Generate the HMAC SHA-256 key object using the byte array of the secret key.
- Concatenate a string of the required information listed above.For more information, seeCreating the Validation Stringbelow.
- Generate a byte array of the validation string.
- Use the HMAC SHA-256 key object to create the HMAC SHA-256 hash of the validation string byte array.
- 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 GenerateSignatureFromParams(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: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:
|
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="