Freedom Chat White Paper

If you would like to read our encryption analysis with snippets of our code you can by clicking here – 1/15/24


Starting from the notions of symmetric & asymmetric encryption, here are some definitions related to Freedom Chat’s protocols*.


A public/private key pair used by a User to sign and authenticate.


A public/private key pair used by a User to encrypt and decrypt a message.


An Identity is the combination of a SigningKey and an EncryptionKey of a User. We can speak of the “private part” or the “public part” of an Identity to designate respectively the private or public keys of the Identity.

The keys of an Identity may be renewed, and an Identity may be revoked.

An Identity is sometimes called a “Device” or “Key” and is referred to by its id generated by the server when it is created and may be called “deviceId” or keyId”.

Chain of Signatures

A mechanism for verifying the integrity of a User‘s Identity is available.

In a simplified way, each operation of creation, renewal of keys or revocation of an Identity is recorded in a chain (the Sig-Chain) in the form of a block. Each block contains the transaction information and the hash of the previous block.

Each block addition to the chain is signed by the SigningKey of a valid Identity of that User, except for the first block which is self-signed.  


A Session is an element to be protected such as a string of characters.


At the beginning of the encryption, the SDK makes a request to our servers* in order to assign to the Session a unique identifier called SessionID.

Messsage Key

This is the term used for the symmetric key needed to decrypt a Session.


This is a MessageKey protected end-to-end using the public key of the EncryptionKey of a Message recipient. The private key of the EncryptionKey recipient is required to recover a MessageKey from an EncryptedMessageKey.

Freedom Chat Registration

  1. When a user first installs Freedom Chat, the application generates two asymmetric key pairs. The first is used to prove his (or her) identity, called signingKey, and the second is used for encryption, called encryptionKey;
  2. The two public keys are then sent to our servers, and an identity is created for this user (on the backend–SealdID);
  3. The account chain of signatures is initialized with a key creation transaction, adding these keys.
  4. To authenticate, the user makes a request to the servers, which will answer a “challenge” to be signed with his signingKey in order to prove his identity. This operation is completely transparent to the user and does not require any password.


The encryption of a Session (Message) by a user using Freedom Chat is done as follows:

  1. MessageKey is generated when a user creates a new chat session. 
  2. If the recipients of the Session are not cached in the application, the public keys to their encryptionKey are retrieved from our servers.*
  3. For each public key thus retrieved, an EncryptedMessageKey is thus generated locally on the user’s mobile device wishing to encrypt the Session.
  4. The Freedom Chat user then makes a request to our servers* to generate a SessionID. To this request is also attached all EncryptedMessageKey so that they can be retrieved by their respective recipients.
  5. From the Session encrypted using the MessageKey and SessionID, the file is then generated, ready to be sent to the recipients.


Once a Session is protected, the decryption of the Session by the intended recipient is done as follows:

  1. The SessionID and the encrypted form of the Session can be retrieved
  2. A request is made to our servers* to check if an EncryptedMessageKey corresponding to the SessionID exists for the user(s);
  3. From the EncryptedMessageKey, and using the private key of the encryptionKey, the user can retrieve the MessageKey required to decrypt the message (Session);
  4. The Session is then decrypted in a temporary directory, which checks if the Session name matches the original. If this is not the case, an alert will be sent to the user.

Security Code

FreedomChat allows you to compare security code, to verify the integrity of encryption keys with your contacts, either manually or with a QRCode. To do this, the phone numbers of all participants in a chat are associated with the hash of the last block of their SigChain.

This is then all encoded in a predictable format, then hashed. This hash is then displayed to the user, and encoded as a QRCode. When comparing manually, or scanning the other’s QRCode, the hash is then compared, which ensures that the contact’s SigChain is as expected, which guarantees that their encryption keys have not been tampered with.

Cryptographic Mechanisms

Here you will find a brief definition of the cryptographic mechanisms used by Freedom Chat.

Randomness Generation

Depending on the target environment, different random generators are used:

Asymmetric Key Pair Generator

The keys used are of type RSA (see RFC 8017).

Depending on the target environment, different asymmetric key pair generators are used:

Symmetric Encryption

To encrypt symmetrically, two algorithms are used to ensure both confidentiality and integrity: an encryption scheme that provides confidentiality only, and a MAC to ensure integrity.


Two symmetric keys are used

  • a 256-bit encryption key noted encryptionKey;
  • a 256-bit key for the MAC, noted authenticationKey.

Their concatenation in this order is noted messageKey.


Keys are used for an indefinite period of time for the data (conversations) they protect.


Symmetric encryption of clearText with a messageKey (concatenation of encryptionKey and authenticationKey) to obtain cipheredMessage is done as follows

  • generation of a random initialization vector denoted iv of 128 bits;
  • encryption:
  • MAC:
    • algorithm: HMAC-SHA-256 (see RFC 6234 §8.3);
    • argument (message_array in RFC 6234): the concatenation of iv and cipherText;
    • key (key in RFC 6234): authenticationKey;
    • result: hmac;
  • return: cipheredMessage which is the concatenation of iv, cipherText, and hmac.


Symmetric decryption of cipheredMessage (concatenation of iv, cipherText, and hmac) with a messageKey (concatenation of encryptionKey and authenticationKey) to obtain clearText is done as follows:

  • MAC:
    • algorithm: HMAC-SHA-256 (see RFC 6234 §8.3);
    • argument (message_array in RFC 6234): the concatenation of iv and cipherText;
    • key (key in RFC 6234): authenticationKey;
    • result: hmac;
  • comparison of hmac with hmac2, if equal continue;
  • decryption:
  • return clearText.

Asymmetric Cryptography

The keys used are of type RSA (see RFC 8017).

One pair of keys is reserved for encryption operations, another for signature operations.


The keys are generated with a modulus n of 4096 bits and a public exponent e of 65537.


These keys are generated for a duration not exceeding 157680000 seconds (5 years), with a default lifetime of 94608000 seconds (3 years).

Asymmetric Encryption

The asymmetric encryption of a clearText with a public key (n,e) given to obtain cipheredMessage is performed as follows

  • computing a checksum of type CRC32 (see POSIX.1-2017 §chksum) on clearText to give crc32 of length 32 bits;
  • encryption:
    • RSAES-OAEP algorithm (see RFC 8017 §7.1.1) with the following parameters:
      • SHA1 as the hash function
      • MGF1-SHA1 (see RFC 8017 §B.2.1) as the mask generation function
      • the L label left empty
    • argument (noted M in RFC 8017 §7.1.1): concatenation of crc32 and cleartext
    • key used (noted (n,e) in RFC 8017 §7.1.1): public key of the recipient
    • result `cipheredMessage
  • return: cipheredMessage

Asymmetric Decryption

Asymmetric decryption of a cipheredMessage with a private key denoted K given to obtain clearText is performed as follows:

  • decryption:
    • RSAES-OAEP algorithm (see RFC 8017 §7.1.2) with the following parameters:
      • SHA1 as the hash function;
      • MGF1-SHA1 (see RFC 8017 §B.2.1) as mask generation function;
      • the L label left empty;
    • argument (noted C in RFC 8017 §7.1.2): concatenation of crc32 and cleartext;
    • key used (noted K in RFC 8017 §7.1.2): private key of the recipient;
    • result decipheredMessage;
  • decompose decipheredMessage into crc32 and clearText;
  • compute a checksum of type CRC32 (see POSIX.1-2017 §chksum) on clearText to give crc32-2 of length 32 bits;
  • compare crc32 and crc32-2, if equal continue;
  • return: clearText.
* Our servers (Freedom Chat’s) and our protocols (Freedom Chat’s) and Seald’s servers and Seald’s protocols may be used in interchangeable language on this page. Seald, our end-to-end encryption partner has been audited by specialized independent companies and has a certification from the French national cybersecurity agency. Freedom Chat does not store messages on our servers. 

Chain of Signatures


A signature chain is a series of ordered blocks, each consisting of a transaction and its signature.

  • Each transaction contains an operation, as well as its position in the chain, its creation timestamp and the hash of the previous transaction.
  • Each block signature contains the hash of the associated transaction, and the signature of that hash.


Each user account is associated with a signature chain, in which all operations concerning the keys of this account are recorded.
This allows any user to verify the integrity of the keys of any account, without having to trust a third party. Thus, even if Seald are ever compromised, the integrity of user accounts is protected.


Each block in the Seald signature chain consists of a transaction, a signature, and possibly additional information. The hash function used for the signature chain is SHA-256. Each transaction contains one operation, which can be the creation, renewal, or revocation of a key. Keys have a validity period. This period is up to five years. By default, we use a validity period of three years.

The signature chain is initialized as soon as the account is created. A transaction is created at position 0, containing a creation operation, and must be signed by the signature key of the new device.

The following transactions can be the creation or revocation of a device, or the renewal of its private keys. The creation and renewal must be signed by a key already registered in the chain, and during its validity period.

When adding or renewing a key, the public signing key must be provided in the “extras” part of the block.

Revocation operations can be unsigned, if they are performed by the Team’s administrator, or by the server (for example in case of expiry)


A transaction consists of two parts: some chain of signature properties, and the key operation.


The chain of signature properties are :

  • position : the position in the chain.
  • previous_hash : the hash of the previous transaction.
  • timestamp : the timestamp of the transaction creation, in seconds since the UNIX epoch.
  • created_at : the timestamp of the transaction creation, in seconds since the UNIX epoch.
  • expire_at : the expiry timestamp of the key, in seconds.
  • sign :
    • user: The signer id.
  • device_id: The id of the key used to sign.



An operation is composed of :

  • type : the type of operation, among “creation”, “renewal” and “revocation”.
  • device :
  • id : The id of the key concerned by the operation.
  • encryption_pubkey_hash : The hash of the public encryption key concerned.
  • signing_pubkey_hash : The hash of the public signing key concerned.

For a key addition or renewal operation, it is necessary to provide the full signing public key, encoded in base 64, in the transaction extras part.


  • protocol : the signature protocol.
  • hash : the hash of the associated transaction.
  • signature : the signature of the hash, by the key specified in the transaction properties.

Block Example

  "transaction": {
    "properties": {
      "position": {"type": "integer"},
      "previous_hash": {"type": "string"},
      "timestamp": {"type": "string"},
      "signer": {
        "user": {"type": "string"},
        "device_id": {"type": "string"}
      "created_at": {"type": "integer"},
      "expire_at": {"type": "integer"},
      "operation": {
        "type": {"type": "string", "enum": ["creation", "renewal", "revocation"]},
        "device": {
          "id": {"type": "string"},
          "encryption_pubkey_hash": {"type": "string"},
          "signing_pubkey_hash": {"type": "string"}
  "signature": {
    "protocol": {"type": "string"},
    "hash": {"type": "string"},
    "signature": {"type": "string"}
  "extras": {
    "pubkeys": {"type": "string"}

Leave a Reply

Your email address will not be published. Required fields are marked *