Summary
This feature gives users the capability to communicate securely through Political Bullpen, by using an end-to-end encryption scheme. Most of this feature’s logic is implemented on the client-side and the server-side handles only public or encrypted information. It does not encrypt any post metadata, such as names of participants in the conversation, posted time, likes, small actions, etc; uploads are encrypted, but their presence is not because the system must associate uploads with posts to prevent deleting them.
The whole code is open-source and security enthusiasts are welcome to review it. For any further information, do not hesitate to contact me - via encrypted message
Three easy steps to use this feature:
-
Go to your preferences and enable encryption (generate new private key) and activate it (on current device) DO NOT LOSE THE PAPER KEY CODE WORDS - THIS IS IMPORTANT
-
send an encrypted message (to a user who also enabled encryption) - there will be a lock icon in the message editing window - when sending a message to a user that has also enabled encryption, the lock will turn green.
-
read decrypted messages - be sure to enter your passphrase from the PAPER KEY on all devices that you use to access Political Bullpen.
Technical information
The goal of this feature is to offer integrity and confidentiality of the encrypted contents, and to protect it against information leaks and unauthorized users. The following sections describe the usual operation mode, used algorithms and threat models.
To use this system, users enroll once by generating a “user identity” consisting of two 4096-bits RSA keys, one for encryption and another for signing. Users can export their “identity” for safe keeping or store it on the server, encrypted after generating a paper key. These two methods serve as backups or are used to enroll new devices.
Creating an encrypted post
To create a new post, the user (their browser) will:
- sign the current post content using their private signing key;
- generate a new “topic key” (a AES-256-GCM key) - which is going to be used to encrypt the post, some post metadata and the title of the new topic (if available);
- fetch the public keys of all participants and encrypt the “topic key” for each of them;
- send to the server the encrypted post (Base64 encoded) and the encrypted topic keys (also Base64 encoded) of each participant.
Paper keys (inspired by RFC 1751 and BIP-39) are human-readable keys that are used to securely store the “user identity” on the server. A paper key consists of 12 random words, picked from a list of 2048 words, offering 121-bits of entropy (the first word is used as a label). To encrypt the “user identity” with a paper key, the system will first derive the encryption key using PBKDF2 to stretch the paper key into a 256-bit AES-GCM key.
Reading an encrypted post
To read a post, the user (their browser) will:
- fetch the encrypted post payload (post plaintext and signature) and encrypted topic key;
- use their private encryption key to decrypt the encrypted topic key;
- use the decrypted topic key to decrypt the encrypted post payload;
- fetch the public signing key of the poster and verify the post signature.
Algorithm Suite
This feature makes extensive use of the cryptographic primitives implemented in Web Crypto API , which are available in any modern browser (except Internet Explorer).
-
getRandomValues
PRNG : It generates paper keys and 96-bits random IVs. - PBKDF2 : It stretches the 132-bit paper keys to 256-bit keys, used for encrypting “user identities”.
- AES-256-GCM : Used to encrypt each post’s content. It also offers authentication by producing an authentication tag of 128-bits, but this is a less important aspect because posts are verified using a signature generated by the poster (see step 1 above).
- RSA-OAEP : Used to encrypt “topic keys” and “user identites” for safe-keeping on the server. All RSA-OAEP keys are 4096-bits long.
- RSA-PSS : Used to sign each post’s content for verifying authenticity. All RSA-PSS keys are 4096-bits long.
Primitives
The system uses a set of primitives built on top of those provided by the browser via Web Cryptography API .
-
encrypt and decrypt : Used to encrypt and decrypt post contents.
encrypt
takes a JSON, an AES-256-GCM key and a RSA-PSS public key and outputs a single Base64 encoded string;decrypt
takes a Base64 encoded string and an AES-256-GCM key and outputs the initial JSON object; - verify : Used to verify post contents after decryption;
- exportKey and importKey : Used to export and import “topic keys”;
- exportIdentity and importIdentity : Used to export and import “user identities”.
Types of keys:
-
topic keys (AES-256-GCM)
- used to encrypt each post in a topic (posts are individually encrypted)
- are generated per topic, on the client-side by the original poster using WebCrypto’s API
generateKey
primitive - are encrypted with user’s public key for every user that has access to the specific topic using WebCrypto’s API
wrapKey
primitive - are stored (encrypted) on the server-side for each user in
PluginStore
-
RSA key-pair (public and private keys) (RSA-OAEP and RSA-PSS, 4096-bits)
- used to encrypt all topic keys a user has access to
- are generated per user on the client-side by the original poster using WebCrypto’s API
generateKey
primitive and shared amongst all of user’s devices - server-side : public identity is stored as exported by the client, but the private identity will always be encrypted with the passphrase key
-
client-side : public and private keys are stored as
CryptoKey
in IndexedDb; if not possible, it will usewindow.localStorage
(in Safari)
-
passphrase keys (derived using PKBDF2 with 128,000 iterations)
- used to encrypt “user identities” for safe storage on the server
- derived from a paper key (or user’s passphrase for legacy purposes)
Threat models
Compromised Instance
An attacker which can inject code could in theory access encrypted information by serving malicious code, which decrypts the encrypted content and sends the plaintext posts to another server. To make this possible, it is enough to have access to an administrator account and create a theme component with the malicious code - this would be impossible to do unless you were the site admin.
Default protection mechanisms such as CSP are in place can detect and mitigate Cross Site Scripting (XSS) attacks that could also represent a way of injecting malicious code.
Man-in-the-Middle Attack
In Man-in-the-Middle attacks, the attacker intercepts the communication between the user and server, giving them the ability to read or alter it. Because this feature encrypts everything before sending, an attacker cannot decrypt anything by simply eavesdropping. Similarly, because information is authenticated the attacker cannot alter it.
However, the attacker could serve malicious code back to the user and follow a similar attack to the one presented in the previous section. This is partially mitigated by HTTPS, which is considerably reducing the attack probability.