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)