Enclave is your command-line secure encrypted deniable cloud-synchronized notebook.
Enclaves can be accessed from anywhere with a simple, memorizable word passphrase (without an accompanying username) and benefit from blazing-fast synchronization. Enclave notebooks are authenticated yet anonymous, provide plausible deniability and self-destruction features, and are highly portable thanks to their passphrase access system, which in practice works in a way similar to cryptocurrency wallets.
Enclave notebooks benefit from strong encryption. The Enclave command-line notebook editor is simple yet full-featured, and works on all major operating systems.
Each Enclave notebook can be set up to work with an optional decoy notebook: when a decoy notebook is accessed, its paired notebook is wiped from the Enclave server. It is not possible for an attacker who does not have access to the server to determine if any Enclave notebook is a decoy notebook or if it is paired to a decoy notebook, or if an Enclave passphrase points to a wiped notebook.
Feel free to pull this down, compile it and try it out:
git clone https://github.com/symbolicsoft/enclave
cd enclave
go run github.com/symbolicsoft/enclave/v2/cmd/enclave
Enclave is currently in a "minimum viable product" stage. There's a barebones featureset which works okay, probably. Don't expect anything more than that as of right now -- there aren't even any versioned releases yet.
Enclave Protocol is meant to provide highly portable secure notebook synchronization from a light client.
- Alice: a local client user who owns a notebook.
- Server: a remote notebook synchronization server.
- Confidentiality: Notebook contents are only visible to Alice.
- Authentication: Notebook contents cannot be undetectably modified by any party other than Alice.
- Anonymity: Enclave notebooks are not tied down to any specific user identifier: the only identifier is a randomly generated passphrase, much like cryptocurrency wallets.
- Deniability and self-destruction: Alice can access different notebooks that quietly wipe paired notebooks based on the provided key material.
- Portability: Notebook access must be predicated on singular, portable (human-readable, memorizable) key material.
Alice's key generation flow looks like this:
Mandatory:
+----------+
| User | PUS = SCRYPT(US, salt, N=2^20, r=8, p=1)
| Secret -------------------------------------->--------+
| (US) | BLAKE2X(PUS) 0 | USK-ID |
+----------+ |--------+
1 | USK-ED |
+--------+
Optional:
+----------+
| Decoy | PDS = SCRYPT(DS, salt, N=2^20, r=8, p=1)
| Secret -------------------------------------->--------+
| (DS) | BLAKE2X(PDS) 0 | USK-DD |
+----------+ |--------+
1 | USK-DX |
+--------+
US
: 12-word mnemonic chosen randomly out of a list of 5459 words.DS
: 12-word mnemonic chosen randomly out of a list of 5459 words.salt
: the byte representation of the 24-byte stringDTWdTA8L9VZG5J8p5dNaUmrQ
.USK-ID
: a string used to identify her notebook to the server.USK-ED
: the notebook 256-bit encryption key.USK-DD
: identifier string, but for the decoy notebook.USK-DX
: decoy notebook 256-bit encryption key.
Whenever Alice updates her notebook, she will be using the same USK-ED
to re-encrypt it. As such, in order to avoid nonce reuse, it becomes crucial to use an extended nonce cipher, which is why we use XChaCha20-Poly1305
, which employs 192-bit nonces.
With 192-bit nonces, the chance of nonce reuse for 100,000,000 encryptions may be estimated as (2^192)/(10^8) ~= 2^169
. These are acceptable numbers, so we can proceed with the chosen key, cipher and nonce size.
The key space passphrases is WordlistSize^PassphraseLength = 5459^12 = 2^149
. These passphrases are run through an expensive Scrypt operation to produce 256-bit hashes, which are then used to derive more 256-bit subkeys.
There is no realistic risk for key collision on the 256-bit hashes or subkeys. However, because all Scrypt hashes are produced with a static salt, an increase in the number of encrypted notebooks means a theoretical increase in the possibility for enumerating a passphrase for some random existing encrypted notebook: if a server has one encrypted notebook, the chance of guessing a random encrypted notebook is (2^149)/1 = 2^149
. If a server has 100,000,000 encrypted notebooks, that chance becomes (2^149)/(10^8) ~= 2^122
. Especially given the very high cost of enumerating the passphrase hash space with the chosen Scrypt parameters, these are acceptable numbers, so we can proceed with the chosen passphrase size.
Enclave uses gRPC as the transport layer, chosen for its speed and efficiency. Transport layer authentication is guaranteed by hardcoding the server's X.509 elliptic-curve public key within the Enclave client.
Alice stores:
(USK-ID, USK-ED)
or(USK-DD, USK-DX)
.- Storing either subkey tuple is completely optional.
- Alice cannot store both keys simultaneously.
Alice can set a small "PIN" used to encrypt stored subkeys. Given that users will have a preference towards this PIN being short and easy to quickly type, we'll be applying Scrypt again (with high cost parameters) when generating the subkey encryption keys from it:
- Alice provides
PIN
. - Enclave generates a random 24-bit
salt
. - Enclave calculates
CEK = SCRYPT(PIN, salt, N=2^20, r=8, p=1)
- Enclave encrypts locally stored subkeys with CEK using XChaCha20-Poly1305 and a random nonce.
Server stores:
- Alice's notebook
NR
under herUSK-ID
. - Alice's decoy notebook
ND
under herUSK-DD
(optional). - Alice's last-used encryption nonce.
From Alice's perspective:
- Alice runs
enclave
for the first time. enclave
asks Alice if she'd like to set up a new notebook. Alice says yes.enclave
checks if it's able to open a connection toenclave-server
and aborts if not.enclave
generatesUS
and communicates it to Alice.enclave
generatesUSK-ID
and sends it toenclave-server
.enclave
asks Alice if she'd like to set up a decoy notebook. If Alice accepts:enclave
advises Alice that she can quickly generate one using ChatGPT, providing example prompts.enclave
generatesDS
and communicates it to Alice.enclave
generatesUSK-DD
and sends it toenclave-server
along with notebookDS
encrypted withUSK-DX
.enclave
communicatesDS
to Alice.
From Server's perspective:
- Server receives a request to store a tuple of notebooks (
NR
,ND
) under their respective identifiersUSK-ID
andUSK-DD
.ND
andUSK-DD
are optional.
NR
is stored under the identifierUSK-ID
.- Should it exist,
ND
is stored under the identifierUSK-DD
.
- Should it exist,
Upon Alice running enclave
:
enclave
checks ifUS
is stored locally. If it is, we can quickly fetch and decrypt the notebook from Server.US
could potentially be a decoy secret (DS
).
- If
US
is not stored locally, Alice is asked to input her mnemonic. At this point, she may inputUS
or (should it exist)DS
.
From Server's perspective:
- Whenever anyone requests the notebook with identifier
USK-ID
, Server sendsNR
along with its stored last-used encryption nonce. - Whenever anyone requests the notebook with identifier
USK-DD
, Server deletesUSK-ID
andNR
(if not already deleted) and sendsND
. - For any real or decoy notebook identifier that does not exist or has been deleted, Server responds with a "notebook not found" error.
- 64 pages per notebook.
- 64KB per notebook page.
Written by Nadim Kobeissi (Symbolic Software), released under the GNU GPLv2 license.