{"id":16820417,"url":"https://github.com/op/tales-from-the-crypto","last_synced_at":"2025-06-19T23:40:28.638Z","repository":{"id":136988221,"uuid":"419485741","full_name":"op/tales-from-the-crypto","owner":"op","description":"The cryptkeeper will guide you","archived":false,"fork":false,"pushed_at":"2021-10-21T11:26:59.000Z","size":20,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-24T01:42:38.937Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/op.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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":"2021-10-20T20:50:24.000Z","updated_at":"2021-10-21T11:27:01.000Z","dependencies_parsed_at":null,"dependency_job_id":"81b19318-1366-4dfe-8a46-554a6f2147df","html_url":"https://github.com/op/tales-from-the-crypto","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/op%2Ftales-from-the-crypto","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/op%2Ftales-from-the-crypto/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/op%2Ftales-from-the-crypto/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/op%2Ftales-from-the-crypto/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/op","download_url":"https://codeload.github.com/op/tales-from-the-crypto/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244056540,"owners_count":20390740,"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":[],"created_at":"2024-10-13T10:56:41.485Z","updated_at":"2025-03-17T15:25:21.474Z","avatar_url":"https://github.com/op.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Encryption protocol\n\nProof of concept; encryption based on user password.\n\n## TERMINOLOGY\n\n\u003e TODO: improve terminology\n\n * primary   -- the primary key (with a protocol)\n * schemes   -- a set of schemes for different categories\n * scheme    -- a specific encryption key (encrypted with the primary key)\n                for a specific category, protocol and version\n * category  -- a category separates different schemes into groups (eg journaling)\n\n## PROTOCOL\n\nThe protocol flow looks like this:\n\n1. Fetch user's salt from server\n2. Derive primary key from user password and salt\n3. Store primary key on local device (for \"remember me\")\n4. Generate scheme for category (encrypt with random nonce and primary key)\n5. Upload used nonce and encrypted key\n\nIf user changes password:\n\n1. Derive new primary key\n2. Re-encrypt all keys for all schemes\n3. Generate new scheme version with new key for all categories\n4. Upload new schemes\n\n## Algorithms\n\n1. Key derivation: argon2id\n2. Encryption: XChaCha20 Poly1305 IETF\n\nAlternative algorithms:\n1. argon2id + libsodium secretbox (XSalsa20 Poly1305 MAC)\n2. PKDF2 + AES256-GCM\n\n## KNOWN ISSUES\n\n* Values can be copied / moved from one \"database entry\" to another.\n   There is nothing in the \"additional\" data that binds it to a\n   specific entry, only to a specific protocol version.\n\n* The only real category right now is journaling. Is it overkill to think about\n  it?\n\n* If password is changed because previous password was stolen, current\n  encryption keys might be at risk.\n\n* Encrypted keys are stored on server. Alternative would be to not store keys\n  at all. This would force us to re-encrypt all data on password change.\n\n## Example\n\n```\n$ ./index.js 6v78rQHoefeqOPTubwFNNA\nGenerated primary key in 0.780s.\n*** local device\ndata { primary: '$29k1$0$1$$-hQbC3g54I-HkqjmlxKdYmWuMwM3l0AkMf1yNYwZ1pc' }\n*** remote database\nuser {\n  primary: { protocol: '29k1', salt: '6v78rQHoefeqOPTubwFNNA' },\n  schemes: [\n    {\n      key: '$29k1$j$1$eWDp4bT3uvGp8eW_fNLq4GaoEzw_axKB$jExMAJLnqMe5L10qsN4AsAg4P4hQQsH1Z2e7ZVwApxef76ra57GWGHDbEynMn4TF',\n      createdAt: '2021-10-20T20:57:58.878Z'\n    }\n  ]\n}\nentries {\n  value: '$29k1$j$1$-3QCtjQGLm4f1fN9WoP7i8ij0_b3XlF4$pCEmwl6PSTcJvEjjvFL9J6ODUuuYkgw-w90eYxzUGxFMHCw7GK5f9Mku2KvJ5A'\n}\n*** encryption\nencrypted $29k1$j$1$-3QCtjQGLm4f1fN9WoP7i8ij0_b3XlF4$pCEmwl6PSTcJvEjjvFL9J6ODUuuYkgw-w90eYxzUGxFMHCw7GK5f9Mku2KvJ5A\ndecrypted Shave and a haircut, two bits!\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fop%2Ftales-from-the-crypto","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fop%2Ftales-from-the-crypto","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fop%2Ftales-from-the-crypto/lists"}