Skip to main content

Hashing Formula

When both the sender and the receiver of a message independently calculate a digest of the message, it's a proven way to ensure that both sides have the same content. But both sides needs to have a reference that describes how to calculate the digest. This document describes the specification that the Retraced API uses to calculate a message digest.

To calculate the digest, Retraced will build a colon (:) delimited string of all the fields, and then calculate a SHA256 digest. Empty or missing fields are not ignored, but are included in the digest as empty strings. Individual fields are percent-escaped before being added to the string.

The order of the fields is important, and is defined as:

  1. event_id: The string ID that is returned from the Retraced API when calling create event.
  2. action: The action parameter provided when creating an event.
  3. target_id: The ID of the target parameter provided when creating an event. If no target was provided, this is an empty string.
  4. actor_id: The ID of the actor parameter provided when creating an event. If no actor was provided, this is an empty string.
  5. group_id: The ID of the [group]/(/docs/retraced/architecture/groups/) parameter provided when creating an event. If no group was provided, this is an empty string.
  6. source_ip: The IP address sent with the event. If no IP address was known, this is an empty string.
  7. is_failure: An integer ("1" or "0") representation of the is_failure parameter provided when creating an event. This is required, and will default to "0".
  8. is_anonymous: An integer ("1" or "0") representation of the is_anonymous parameter provided when creating an event. This is required, and will default to "0".
  9. fields: A semicolon (;) separated list of the field=value parameters provided in the event. The fields are sorted alphabetically by the key name before encoding. A trailing ; is included, if there are fields. If there are no fields, a single colon (:) should be appended in place of the fields list.

Examples

Simple Event

Given the following login audit event:

{
"action": "user.login",
"group": {
"id": "group-id",
"name": "group-name"
},
"created": "2017-01-01T00:00:00.000000000Z",
"crud": "c",
"description": "User \"someone@someplace.com\" logged in",
"source_ip": "8.8.8.8",
"actor": {
"id": "actor-id",
"name": "actor-name",
"type": "user",
"url": "https://my.site.com/account/actor-id"
},
"is_failure": false,
"is_anonymous": false
}

A string is built with the fields, as described above:

event-id:user.login::actor-id:group-id:8.8.8.8:0:0:

Finally, a SHA256 digest of the above string returns:

1ee7c214a6bc2ab3e4f921b7c98a148357eebb56081fd68d88bd25acdec45332

With Fields

Given the following audit event:

{
"action": "document.share",
"group": {
"id": "group-id",
"name": "group-name"
},
"created": "2017-01-01T00:00:00.000000000Z",
"crud": "u",
"target": {
"id": "target-id",
"name": "document-name",
"type": "document",
"url": ""
},
"description": "Shared document with \"another@user.com\"",
"source_ip": "8.8.8.8",
"actor": {
"id": "actor-id",
"name": "a@user.com",
"type": "user",
"url": "https://my.site.com/account/actor-id"
},
"fields": {
"resulting_permission": "view,edit",
"permission_granted": "view"
},
"is_failure": false,
"is_anonymous": false
}

A string is built with the fields, as described above:

event-id:user.login:target-id:actor-id:group-id:8.8.8.8:0:0:permission_granted=view;resulting_permission=view,edit;

Finally, a SHA256 digest of the above string returns:

e3412f11c1ed3b592d5333441880373ede3b774bc62914ed9317d3affaec9048

Escaping Hash Parameters

Any values used for hashing should have the following replacements applied:

  1. % -- any percent symbols (%) should be converted to %25
  2. : -- any colons (:) should be converted to %3A

Further, any values in the fields section should also have the following escapes applied in a second pass:

  1. = -- any equals signs (=) should be converted to %3D
  2. ; -- any semicolons (;) should be converted to %3B