Encryption

If additional encryption is desired, symmetric encryption using the fernet specification is available.

Why Fernet?

Fernet builds on best practice cryptography methods, and allows developers to provide a simple method of encrypting and authenticating.

Conceptually, fernet takes a user-provided message (an arbitrary sequence of bytes), a key (256 bits), and the current time, and produces a token, which contains the message in a form that can't be read or altered without the key. Overall it uses 128-bit AES symmetric encryption in a CBC mode with PKCS7 padding and HMAC using SHA256 for authentication.

Sources - 1, 2

How to enable encryption

Encryption keys will be set-up during the initial calibration phase with a Unit21 engineer.

HeaderTypeElaboration
u21-fernetStringInclude if encryption is desired

This additional encryption is available for all APIs. The steps to enable encryption are as follows:

  1. Include u21-fernet : true in the request header
  2. Encrypt the payload (e.g. json) using the key
  3. Decrypt the payload response using the key

Example:

LanguageLibrary Required
PythonCryptography
JavaFernet-Java8
JavascriptFernet
import requests
from cryptography.fernet import Fernet

fernet = Fernet(b'<pre-shared-fernet-key>')
encrypted_data = fernet.encrypt(b'{"key": "value"}')

res = requests.post(
    "https://<API_ENDPOINT>/v1/entities/create",
    headers={'u21-key': '<YOUR_API_KEY>', 'u21-fernet': 'True'},
    data=encrypted_data)

decrypted_ciphertext = fernet.decrypt(res.content)
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import com.macasaet.fernet.Key;
import com.macasaet.fernet.StringValidator;
import com.macasaet.fernet.Token;
import com.macasaet.fernet.Validator;

public class EncryptionSample {
    private final static HttpClient httpClient = HttpClient.newBuilder()
            .version(HttpClient.Version.HTTP_2)
            .build();

    private static void sendPost() throws Exception {
        String json = "{\"key\": \"value\"}";
        final Key key = new Key("<pre-shared-fernet-key>");
        final Token token = Token.generate(key, json);

        HttpRequest request = HttpRequest.newBuilder()
                .POST(HttpRequest.BodyPublishers.ofString(token.serialise()))
                .uri(URI.create("https://<API_ENDPOINT>/v1/entities/create"))
                .setHeader("u21-key", "<YOUR_API_KEY>")
                .header("Content-Type", "application/json")
                .header("u21-fernet", "True")
                .build();

        HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());

        final Token tokenResult = Token.fromString(response.body());
        final Validator<String> validator = new StringValidator() {};
        System.out.println(tokenResult.validateAndDecrypt(key, validator));
    }

    public static void main (String[] args) throws Exception {
        sendPost();
    }
}
const axios = require('axios')
var fernet = require('fernet')

const headers = {
	'u21-key': '<YOUR_API_KEY>', 
	'u21-fernet': 'True'
}

fernet.setSecret(<pre-shared-fernet-key>);
const token = new fernet.Token({ time: Date.now() });
const message = token.encode("Message");

axios
  .post('https://<API_ENDPOINT>/v1/entities/create', {
    headers: headers,
    message
  })
  .then(res => {
    var token = new fernet.Token({
      secret: <pre-shared-fernet-key>,
      token: res.data,
      ttl: 0
   })
   token.decode();
  })
  .catch(error => {
    console.error(error)
  })