Data encryption

This handbook describes an internal implementation of encryption algorithms for sending encrypted and signed data from a browser. It serves primarily as a reference when implementing Twisto API without using a prepared library. We currently support two ways of encrypting data that can be changed in settings. If you can not use the ready library for Twisto implementation, we recommend to choose a SecretBox that is easier to implement.

PHP library does the encryption automatically and no settings need to be changed.

AES + HMAC

Data is encrypted using AES-128-CBC and signed with HMAC-SHA256

Data encryption

  • Remove the prefix (the first 8 characters) from your secret key. Convert the chain from hexadecimal code to binary data. From these data, use the first 16 bytes as the key for the cipher. Use the rest of the data as salt for the digest.
  • Generate cryptographically random initialization vector iv.
  • Use the key and vector iv to get the cipher.
  • Convert the data to UTF-8 and compress the resulting string using the zlib library.
  • Add string length as unsigned long int in network byte order and apply padding to the resulting string.
  • Encrypt the text and together with the vector iv and digest convert it to Base64
import zlib import struct import base64 import binascii from Crypto import Random from Crypto.Cipher import AES from Crypto.Hash.HMAC import HMAC from Crypto.Hash.SHA256 import SHA256Hash import json # get key and salt key_part = secret_encryption_key[8:] binary_key = binascii.unhexlify(key_part) key, salt = binary_key[:16], binary_key[16:] # Initialization vector iv = Random.new().read(AES.block_size) # get cipher. cipher = AES.new(key, AES.MODE_CBC, iv) # conversion to UTF-8 serialized_data = json.dumps(data).encode('utf-8') # data compression serialized_data = zlib.compress(serialized_data, 9) # attach data size in bytes (big-endian) serialized_data = struct.pack('!L', len(serialized_data)) + serialized_data # checksum digest = HMAC(salt, serialized_data + iv, SHA256Hash()).digest() # padding serialized_data += bytes(16 - len(serialized_data) % 16) # encryption encrypted_data = cipher.encrypt(serialized_data) payload = str(base64.b64encode(iv + digest + encrypted_data), encoding='utf-8')

SecretBox

Encryption is implemented by the open source Sodium library, which is based on the cryptographic library NaCl. The library is written in C, but there are many different implementations for other languages.

Data encryption

  • Remove the prefix (the first 8 characters) from your secret key. Convert the string from hexadecimal code to binary data. From these data, use the first 16 bytes as the key for the cipher.
  • Create a random nonce using a safe random number generator. Each nonce can be used only once. The random number generator must be safe for cryptographic use, so we strongly recommend using the generator provided by the Sodium library.
  • Encrypt using the Sodium library.
import binascii from nacl import encoding from nacl.secret import SecretBox from nacl.utils import random # remove prefix key_part = secret_encryption_key[8:] # get binary key en_key = binascii.unhexlify(key_part) # get random nonce box = SecretBox(en_key, encoder=encoding.RawEncoder) nonce = random(SecretBox.NONCE_SIZE) # encryption str = box.encrypt(data, nonce, encoder=encoding.Base64Encoder)