{"id":13593415,"url":"https://github.com/symbolicsoft/enclave","last_synced_at":"2026-01-12T06:53:10.865Z","repository":{"id":214970014,"uuid":"733110869","full_name":"symbolicsoft/enclave","owner":"symbolicsoft","description":"Command-line secure encrypted deniable cloud-synchronized notebook","archived":false,"fork":false,"pushed_at":"2024-01-02T15:09:18.000Z","size":1012,"stargazers_count":111,"open_issues_count":3,"forks_count":7,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-04-05T19:42:35.268Z","etag":null,"topics":["encrypted-notebook"],"latest_commit_sha":null,"homepage":"https://enclave.sh","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/symbolicsoft.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-12-18T15:31:34.000Z","updated_at":"2025-01-10T13:28:45.000Z","dependencies_parsed_at":"2024-01-01T16:22:58.603Z","dependency_job_id":"87bad9bb-b544-4e63-9cab-844080ac0b74","html_url":"https://github.com/symbolicsoft/enclave","commit_stats":null,"previous_names":["symbolicsoft/enclave"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/symbolicsoft%2Fenclave","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/symbolicsoft%2Fenclave/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/symbolicsoft%2Fenclave/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/symbolicsoft%2Fenclave/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/symbolicsoft","download_url":"https://codeload.github.com/symbolicsoft/enclave/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247980829,"owners_count":21027803,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["encrypted-notebook"],"created_at":"2024-08-01T16:01:20.072Z","updated_at":"2025-04-09T04:34:11.877Z","avatar_url":"https://github.com/symbolicsoft.png","language":"Go","funding_links":[],"categories":["Go"],"sub_categories":[],"readme":"# Enclave\n\n![Enclave Screenshot](assets/screenshot.png)\n\n**Enclave** is your command-line secure encrypted deniable cloud-synchronized notebook.\n\nEnclaves 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.\n\nEnclave notebooks benefit from strong encryption. The Enclave command-line notebook editor is simple yet full-featured, and works on all major operating systems.\n\nEach 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.\n\n## Project Status\n\nFeel free to pull this down, compile it and try it out:\n\n```bash\ngit clone https://github.com/symbolicsoft/enclave\ncd enclave\ngo run github.com/symbolicsoft/enclave/v2/cmd/enclave\n```\n\nEnclave 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.\n\n## Technical Specification\n\nEnclave Protocol is meant to provide highly portable secure notebook synchronization from a light client.\n\n### Principals\n\n- **Alice**: a local client user who owns a notebook.\n- **Server**: a remote notebook synchronization server.\n\n### Security Properties\n\n- **Confidentiality**: Notebook contents are only visible to Alice.\n- **Authentication**: Notebook contents cannot be undetectably modified by any party other than Alice.\n- **Anonymity**: Enclave notebooks are not tied down to any specific user identifier: the only identifier is a randomly generated passphrase, much like cryptocurrency wallets.\n- **Deniability and self-destruction**: Alice can access different notebooks that quietly wipe paired notebooks based on the provided key material.\n- **Portability**: Notebook access must be predicated on singular, portable (human-readable, memorizable) key material.\n\n### Key Generation\n\nAlice's key generation flow looks like this:\n\n```text\n Mandatory:\n+----------+\n|  User    | PUS = SCRYPT(US, salt, N=2^20, r=8, p=1)\n|  Secret  --------------------------------------\u003e--------+\n|  (US)    | BLAKE2X(PUS)                      0 | USK-ID |\n+----------+                                     |--------+\n                                               1 | USK-ED |\n                                                 +--------+\n Optional:\n+----------+\n|  Decoy   | PDS = SCRYPT(DS, salt, N=2^20, r=8, p=1)\n|  Secret  --------------------------------------\u003e--------+\n|  (DS)    | BLAKE2X(PDS)                      0 | USK-DD |\n+----------+                                     |--------+\n                                               1 | USK-DX |\n                                                 +--------+\n```\n\n- `US`: 12-word mnemonic chosen randomly out of a list of 5459 words.\n- `DS`: 12-word mnemonic chosen randomly out of a list of 5459 words.\n- `salt`: the byte representation of the 24-byte string `DTWdTA8L9VZG5J8p5dNaUmrQ`.\n- `USK-ID`: a string used to identify her notebook to the server.\n- `USK-ED`: the notebook 256-bit encryption key.\n- `USK-DD`: identifier string, but for the decoy notebook.\n- `USK-DX`: decoy notebook 256-bit encryption key.\n\n#### Note on Key Reuse\n\nWhenever 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.\n\nWith 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.\n\n#### Note on Key Enumeration\n\nThe 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.\n\nThere 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.\n\n### Transport Layer\n\nEnclave uses [gRPC](https://grpc.io) 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.\n\n### Storage \u0026 Synchronization\n\n#### Alice\n\nAlice stores:\n\n- `(USK-ID, USK-ED)` **or** `(USK-DD, USK-DX)`.\n  - Storing either subkey tuple is completely optional.\n  - Alice cannot store both keys simultaneously.\n\nAlice 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:\n\n1. Alice provides `PIN`.\n2. Enclave generates a random 24-bit `salt`.\n3. Enclave calculates `CEK = SCRYPT(PIN, salt, N=2^20, r=8, p=1)`\n4. Enclave encrypts locally stored subkeys with CEK using XChaCha20-Poly1305 and a random nonce.\n\n#### Server\n\nServer stores:\n\n- Alice's notebook `NR` under her `USK-ID`.\n- Alice's decoy notebook `ND` under her `USK-DD` (optional).\n- Alice's last-used encryption nonce.\n\n### User Flow\n\n#### First Run\n\nFrom Alice's perspective:\n\n1. Alice runs `enclave` for the first time.\n2. `enclave` asks Alice if she'd like to set up a new notebook. Alice says yes.\n3. `enclave` checks if it's able to open a connection to `enclave-server` and aborts if not.\n4. `enclave` generates `US` and communicates it to Alice.\n5. `enclave` generates `USK-ID` and sends it to `enclave-server`.\n6. `enclave` asks Alice if she'd like to set up a decoy notebook. If Alice accepts:\n    - `enclave` advises Alice that she can quickly generate one using ChatGPT, providing example prompts.\n    - `enclave` generates `DS` and communicates it to Alice.\n    - `enclave` generates `USK-DD` and sends it to `enclave-server` along with notebook `DS` encrypted with `USK-DX`.\n    - `enclave` communicates `DS` to Alice.\n\nFrom Server's perspective:\n\n1. Server receives a request to store a tuple of notebooks (`NR`, `ND`) under their respective identifiers `USK-ID` and `USK-DD`.\n    - `ND` and `USK-DD` are optional.\n2. `NR` is stored under the identifier `USK-ID`.\n    - Should it exist, `ND` is stored under the identifier `USK-DD`.\n\n#### Subsequent Runs\n\nUpon Alice running `enclave`:\n\n1. `enclave` checks if `US` is stored locally. If it is, we can quickly fetch and decrypt the notebook from Server.\n    - `US` could potentially be a decoy secret (`DS`).\n2. If `US` is not stored locally, Alice is asked to input her mnemonic. At this point, she may input `US` or (should it exist) `DS`.\n\nFrom Server's perspective:\n\n1. Whenever anyone requests the notebook with identifier `USK-ID`, Server sends `NR` along with its stored last-used encryption nonce.\n2. Whenever anyone requests the notebook with identifier `USK-DD`, Server **deletes** `USK-ID` and `NR` (if not already deleted) and sends `ND`.\n3. For any real or decoy notebook identifier that does not exist or has been deleted, Server responds with a \"notebook not found\" error.\n\n### Restrictions\n\n- 64 pages per notebook.\n- 64KB per notebook page.\n\n## Author\n\nWritten by Nadim Kobeissi (Symbolic Software), released under the GNU GPLv2 license.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsymbolicsoft%2Fenclave","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsymbolicsoft%2Fenclave","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsymbolicsoft%2Fenclave/lists"}