Message Format

This section explains the SpeedSentry message format.

Goals

The message format used by SpeedSentry is designed to provide a reasonably light-weight, secure, interface between your infrastructure and SpeedSentry infrastructure. More specifically, the message format provides:

  • A secure authentication mechanism to prevent spoofing or highjacking of your account,

  • the ability to thwart replay attacks,

  • safe operation with different character encodings, and

  • the ability to operate across 8-bit unsafe transport mechanisms.

Account Secrets

Your account will include two critical pieces of information, a customer identifier and a 56-byte long secret.

You can locate both values on the “REST API” page under the “Settings” page after logging in.

If needed, you can also regenerate a new secret for your account. Note that doing so will immediately disable any existing REST API and your WordPress plug-in until you update your secret used for your REST API as well as reconnect to Inesonic infrastructure from your WordPress plug-in.

Customer Identifier

The customer identifier is a 64-bit hexidecimal value that is used to identify you. Your customer identifier is unique to you and will never change. The customer identifier is case insensitive.

Secret

The secret is a 56-byte long randomly generated value that is tied to your account. You can regenerate a new secret at any time although doing so will require you to update your REST API and will require you to reconnect your WordPress plug-in to Inesonic infrastructure.

We present the secret as a base-64 encoded string. You will need to decode the secret before applying it.

Request Format

All messages are sent from your infrastructure to Inesonic infrastructure using HTTP POST method.

HTTP POST Format

You should include the following request headers in the messages:

  • Content-Type : application/json

  • Content-Length: <total length in bytes>

The message sent to our infrastructure should be JSON encoded, containing the following three fields:

{
   "cid" : "<customer identifier>",
   "data" : "<base-64 encoded message>",
   "hash" : "<base-64 encoded hash>"
}

The cid field should be your customer identifier presented as a 16 character long hexidecimal value. The cid field is case insensitive.

The data field should be your message, base-64 encoded so that the provided data is 7-bit safe and thus able to move across transport layers that expect or transform data between different character encodings.

The hash field is a base-64 encoded 32-byte long hash generated from your raw data and secret, prior to base-64 encoding.

Below is an example message sent via POST:

{
    "cid": "6e6cb5cd0d2dad53",
    "data": "eyJvcmRlcl9ieSI6ICJtb25pdG9yX2lkIn0=",
    "hash": "CmORepo1AJW0mhFe6Sadn2WSIa74JhiaDddxb9RMTFc="
}

Encoded Data

Your request data should be provided as a JSON encoded string using any of the character encodings below:

  • 7-bit ASCII,

  • Latin 1 (ISO 8851-1),

  • UTF-8 (ISO 10646)

  • IEC/ISO 2022

  • Any other 8-bit encoding formats based on ASCII.

Note

At this time we do not support UTF-16 or similar wide encoding formats.

Hash

You should generate a time-based hash using your 56-byte long secret and the JSON encoded data:

  • Determine the current Unix timestamp on your system, \(t_{unix}\). The value should represent the number of seconds that have elapsed since midnight, January 1, 1970 UTC.

  • Calculate a time index from the Unix timestamp using the equation below. The \(t_d\) value is used to adjust for clock error between your system and Inesonic, LLC infrastructure and will normally be 0. We provide a REST API you can use to determine this correction factor. For details, see Time Correction.

\[t_{index} = \left \lfloor \frac{t_{unix} + t_d}{30} \right \rfloor\]
  • Convert the time index value to an 8-byte long little-endian representation and append to your secret to create a 64-byte long time dependent secret.

  • Calculate a 32-byte SHA-256 HMAC from your JSON encoded data using the 64-bit secret as your key.

  • Base-64 encode both your JSON encoded message to be used as the data field and your 32-byte long SHA-256 HMAC to be used as the hash field.

The example code below demonstrates this algorithm as implemented in Python 3:

import time
import struct
import hashlib
import hmac
import json
import base64
import requests

# Get our Unix timestamp.

t_unix = int(time.time())

# Note // indicates integer division (rounding down)

t_index = (t_unix + t_d) // 30

# Create our 64-byte long time dependent secret.

key = my_secret + struct.pack('<Q', t_index)

# Calculate a SHA-256 HMAC.
#   Note: raw_message is our JSON encoded message in one of the
#         acceptable character sets listed above.

raw_hash = hmac.new(
    key = key,
    msg = raw_message,
    digestmod = hashlib.sha256
).digest()

# Base-64 encode both our message and our hash so they're 7-bit safe.

encoded_message = base64.b64encode(raw_message)
encoded_hash = base64.b64encode(raw_hash)

payload =json.dumps(
    {
        'cid' : customer_identifier,
        'data' : encoded_message.decode('ascii'),
        'hash' : encoded_hash.decode('ascii')
    }
)

# Send our request and wait for a response.  The URL is the full URL to
# the endpoint we're sending our request to.

response = requests.post(
    url,
    data = payload,
    headers = {
        'Content-Type' : 'application/json',
        'Content-Length' : str(len(payload))
    }
)

On success, Inesonic, LLC Infrastructure will return 200 status along with the requested data. If the hash and data do not match, Inesonic, LLC infrastructure will return HTTP 401 status (UNAUTHORIZED).

If you receive an HTTP 401 (UNAUTHORIZED) error, you can use the /td endpoint documented in Time Correction to determine the required time adjustment.

Note

Inesonic, LLC infrastructure has the ability to detect small time errors between the sender and receiver and will be resilient to time errors up-to \(\pm 30\) seconds.

Response Format

For the majority of messages, the response will be a JSON encoded data structure with the requested data. A very few messages that provide images will return those images in a binary format.

The response header will include a “Content-Type” value indicating the format of the returned data. You should check the “Content-Type” value for messages that can return binary data as the format may be a JSON encoded payload if an error occurred.

The response header will also populate the “Content-Length” value indicating the number of returned bytes of data.

Time Correction

If you receive a 401 UNAUTHORIZED error, you can query Inesonic, LLC infrastructure for a time correction value, \(t_d\) to be applied when calculating your message hashes.

We recommend that you only apply a correction if you receive a 401 UNAUTHORIZED error and that you cache the correction value for future use. In almost all cases, if you use NTP or a similar mechanism to set your system time, clock errors will small enough that they will not impact your system.

To request a time correction value, use the “/td” endpoint, supplying a JSON encoded payload holding your current system time.

{
    "timestamp" : timestamp>
}

Where <timestamp> is your current Unix timestamp, that is an integer value holding the number of seconds since midnight, January 1, 1970, UTC.

The message requires you to define the following headers:

  • Content-Type : application/json

  • Content-Length : The length of the encoded JSON request message.

The returned response will be JSON encoded and will include a “status” value indicating success (“OK”) or failure. The response will also include a “time_delta” value holding the time delta to be applied when calculate the message hash as described in Hash.

An example response is shown below:

{
    "status" : "OK",
    "time_delta" : 43
}