2

I have a function that is attempting to return a lower case base 16 encoded hash of a request body for signing the AWS API, as detailed in the hashed payload section here.

Given the following JSON string -

{
  "shipTo": {
    "name": "A3",
    "addressLine1": "SWA Test Account",
    "addressLine2": "SWA Test Account",
    "addressLine3": "SWA Test Account",
    "stateOrRegion": "",
    "postalCode": "DN1 1QZ",
    "city": "Doncaster",
    "countryCode": "GB",
    "email": "test+test@amazon.com",
    "phoneNumber": "444-444-4444"
  },
  "shipFrom": {
    "name": "A1",
    "addressLine1": "4 Neal Street",
    "stateOrRegion": "",
    "postalCode": "WC2H 9QL",
    "city": "London",
    "countryCode": "GB",
    "email": "test+test@amazon.com",
    "phoneNumber": "444-444-4444"
  },
  "packages": [
    {
      "dimensions": {
        "length": 3.14,
        "width": 3.14,
        "height": 3.14,
        "unit": "INCH"
      },
      "weight": {
        "unit": "KILOGRAM",
        "value": 3.14159
      },
      "items": [
        {
          "quantity": 1,
          "itemIdentifier": "V-02",
          "description": "Sundries",
          "isHazmat": false,
          "weight": {
            "unit": "KILOGRAM",
            "value": 1.14159
          }
        },
        {
          "quantity": 1,
          "itemIdentifier": "V-01",
          "description": "Sundries",
          "isHazmat": false,
          "weight": {
            "unit": "KILOGRAM",
            "value": 1.14159
          }
        }
      ],
      "insuredValue": {
        "unit": "GBP",
        "value": 29.98
      },
      "packageClientReferenceId": "abcd"
    }
  ],
  "channelDetails": {
    "channelType": "EXTERNAL"
  }
}

I am expecting a return value of 71d826b7bab4af808f73033e81154bce32fed66f1270393d8b0fa05839a6fb29 as displayed in successful postman calls for the same JSON value.

However, I am getting a value of 16f1382cc1db6988693b66e49597811e46f4210c284c82cbc37b6a9f58c61bf5, which throws off subsequent signing values, and causes the call to fail.

Here is the function that takes the JSON string and returns the hash -

public static string HashRequestBody(string stringToHash)
{
    byte[] hashedBytes = new SHA256Managed().ComputeHash(Encoding.UTF8.GetBytes(stringToHash));
    
    StringBuilder sb = new StringBuilder();
    
    for (int i = 0; i < hashedBytes.Length; i++)
    {
        sb.Append(hashedBytes[i].ToString("x2", CultureInfo.InvariantCulture));
    }

    return sb.ToString();
}

What would be causing the differences in hashed payload values in my code as opposed to the Postman call for the same request body?

Luke4792
  • 455
  • 5
  • 19

1 Answers1

0

It turns out that the hash was different due to the line breaks included in my JSON object.

You can read more here, but the short of it is Microsoft uses \r\n for line breaks by default, and the hash Amazon is calculating is using only \n as a line break.

I resolved this by serializing the object to a string and replacing \r\n with the expected \n values, like so:

body = Regex.Replace(body, @"\r\n?|\n", "\n");

Luke4792
  • 455
  • 5
  • 19