Skip to content

End to End Encryption (E2EE) on LiberaForms

After some teasing, we are happy to announce that this feature has landed on dev.liberaforms.org!

That means it is now open for broader testing and will make it into v4, the next version of LiberaForms, which will make your favourite FOSS form software much more useful and interesting.

You can check the user documentation here, so we will be focusing here a tad more on the design and implementation of the feature.

Cryptography bits

Everything related to cryptography (encrypting, decrypting, keys, ...) happens in the client, never on the server.

Upon recommendation by NLnet, we use OpenPGP.js, which appears to be well maintained, has good browser compatibility and in our early testing proved to be reasonable to use.

When it comes to keys and encryption, we mostly rely on OpenPGP.js' reasonable defaults; the only difference is that we are specific about using type: 'ecc', when generating keys (it is also the current default of OpenPGP.js).

ECC keys are asymmetric, which is perfect for our use-case.

Key types

In LiberaForms there are two kinds of keys:

  • form keys: which protect the answers of a given form
  • personal keys: which protect the form keys that a user can access

Personal keys

  • These keys are created by each user, and are exclusive to them
  • This key is only used to encrypt Form Keys
  • The public key gets persisted on the server and is shared with other LiberaForms users, in case a form must be shared with them
  • The private key MAY be protected by a passphrase
  • The private key never, ever, leaves the user's browser
  • The backup functionality places the private key in the clipboard

Form keys

  • These keys are created by a form's owner
  • This key is only used to encrypt Form Answers
  • The public key gets persisted on the server and is public to anyone with access to the form
  • The private key IS protected by the user's personal key
  • The private key, protected by a user's personal key, MAY be persisted on the server:
    • If using the answer sharing function (it uses the new user's public key)
    • If using a remote backup (it uses the current user's public key)
    • Not that even in these cases, the server does NOT have access to the answers, since it cannot decrypt the key

Key storage

We use both localStorage and sessionStorage for different purposes:

  • localStorage: persists a user's private key and their form private keys. User keys are protected by a passphrase if requested, and form keys are protected by the user key always.
  • sessionStorage: persists a user's private key and their form private keys unlocked. This means we only ask for a user key's passphrase once per session.

The feature in action

Form creation

LiberaForms v4 will feature as well an interactive map functionality. This short clip shows the creation of such a form, enabling E2EE afterwards.

User submitting an answer

Note that this is happening before -editor configures E2EE, and obtains access to the form.

If we inspect the POST request, we will see that it does not contain the user-provided data; it only contains a base64-encoded binary blob, which is encrypted with the Form Key, and therefore unreadable by the server.

-editor1 configures keys

Note that -editor1 the UI guides the user through the key creation process and warns about the consequences of losing the key or forgetting the password, requiring them to back up the key.

Adding -editor1 to the form

What is actually happening here is:

  • The form owner queries E2EE data related to this user and this form from the server
  • Since the user exists on the server and has their public key configured, this gets sent to the browser
  • The browser then uses -editor1's public key to encrypt the form key, and saves it on the server associated with -editor1

-editor1 reads answers

When trying to access the Form's answers, LiberaForms will help the user restore the Form key locally, by unlocking it with their private key locally.

The data is never seen by the server.

How can I try it?

You can try this on dev.liberaforms.org!

While this is a release candidate, we want to gather more feedback before releasing it fully, and something might change.

For self-hosed instances you just install/upgrade LiberaForms as usual!

Remember not to use this version and feature on any instance where you care about your data until it is fully released.

However we will try to take care of any migrations necessary between this development version and the definitive release of v4.0, where this feature is enabled by default, but not as a default for new forms.

This can be changed in the settings though!

If you do try this out, let us know and report any bugs you may find!