{"id":20102759,"url":"https://github.com/42loco42/capka","last_synced_at":"2025-07-16T08:34:49.598Z","repository":{"id":229350667,"uuid":"776495883","full_name":"42LoCo42/capka","owner":"42LoCo42","description":"Clientside Argon2 Public-Key Authentication","archived":false,"fork":false,"pushed_at":"2024-03-23T21:16:01.000Z","size":36,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-25T17:06:55.634Z","etag":null,"topics":["argon2","argon2id","caddy-plugin","echo-middleware","go","golang","public-key-cryptography"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/42LoCo42.png","metadata":{"files":{"readme":"README.org","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":"2024-03-23T17:07:47.000Z","updated_at":"2024-06-28T03:10:25.000Z","dependencies_parsed_at":"2024-03-30T15:00:41.678Z","dependency_job_id":null,"html_url":"https://github.com/42LoCo42/capka","commit_stats":null,"previous_names":["42loco42/capka"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/42LoCo42/capka","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/42LoCo42%2Fcapka","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/42LoCo42%2Fcapka/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/42LoCo42%2Fcapka/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/42LoCo42%2Fcapka/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/42LoCo42","download_url":"https://codeload.github.com/42LoCo42/capka/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/42LoCo42%2Fcapka/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265497758,"owners_count":23777058,"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":["argon2","argon2id","caddy-plugin","echo-middleware","go","golang","public-key-cryptography"],"created_at":"2024-11-13T17:32:57.301Z","updated_at":"2025-07-16T08:34:49.547Z","avatar_url":"https://github.com/42LoCo42.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"* Clientside Argon2 Public-Key Authencation\nAn interesting way of enabling asymmetric cryptography\nwithout having to carry around certificate or key files.\n\n** The basic protocol (v0)\n1. the client obtains a username \u0026 password, e.g. via a login form\n2. from these, it computes a master keypair using the argon2id algorithm:\n   #+begin_src go\n     // inputs\n     username := \"alice\"\n     password := \"hunter2\"\n     domain := \"example.org\"\n\n     // standard values, set by the crypto library\n     SEEDBYTES := 32 // required by sign_seed_kp\n     SALTBYTES := 16 // required by argon2id\n     OPSLIMIT_INTERACTIVE := 2\n     MEMLIMIT_INTERACTIVE := 67108864 // 64 MiB\n\n     seed := argon2id(\n         SEEDBYTES, // output length\n         password,\n         hash(SALTBYTES, username+domain), // salt\n         OPSLIMIT_INTERACTIVE,\n         MEMLIMIT_INTERACTIVE,\n     )\n     kp := sign_seed_kp(seed)\n   #+end_src\n3. server: exposes a =/capka/login= endpoint\n   - client: GETs the endpoint:\n   - this returns a \"nonce\" (can be any random string)\n   - server keeps all nones in an \"active\" cache for a short amount of time (e.g. 5 seconds)\n4. the client POSTs to the same endpoint the following structure:\n   #+begin_src jsonc\n     {\n         \"user\": \"\u003cthe given username\u003e\",\n         \"nonce\": \"\u003cnonce returned by GET /capka/login\u003e\",\n         \"signature\": \"\u003cnonce signed with the master keypair\u003e\"\n     }\n   #+end_src\n5. the server then validates both the nonce (is it still in the active cache?)\n   and the signature (user's public keys are stored in the server DB)\n\n** Extension: secure username (v1)\nIn step 4, the =signature= is computed on =user+nonce= instead of just the nonce.\n\n** Extension: simple encrypted return (v2)\nIn step 5, if the server wants to return some kind of session identifier,\nit encrypts it to the client's public key instead of sending it in plaintext.\n\n** Extension: ephemeral encrypted return (v3)\nThe previous extension misuses the client's keypair by assigning it two functions:\nsignature verification and data encryption.\nInstead, the following changes are made:\n- in step 2, the client also creates a random, ephemeral keypair\n- in step 4, the public key of that keypair is added to the structure (field =ephkey=)\n  and the signature is now computed over all three values (user, nonce, ephkey)\n- in step 5, the server encrypts the session ID to the ephemeral pubkey\n  instead of the client master pubkey\n\nThis version of the protocol *should* be completely secure\neven on untrusted (not HTTPS) channels\n(of course the client can't trust the server under those circumstances).\n\nAttackers can't replace any message or component without triggering\nsome kind of validation error on the server.\nAnd since nonces don't carry intrinsic ownership information,\neven a complete replacement of the nonce with another valid one\ndoesn't give the attacker any way of injecting their own user\nor obtaining the session ID.\n\n* Implementation goals\n- a Go library for embedding the login logic into an application (DONE)\n\n- serverside:\n  - a middleware for [[https://echo.labstack.com/][Echo]]\n  - a module for [[https://caddyserver.com/][Caddy]]\n  - both of these should have a pluggable user → pubkey lookup function\n\n- clientside:\n  - a JavaScript library for the browser\n  - a CLI tool for quickly generating client pubkeys (DONE)\n\n- everything will be based on [[http://libsodium.org/][libsodium]]:\n  - https://github.com/jamesruan/sodium\n  - https://github.com/jedisct1/libsodium.js\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F42loco42%2Fcapka","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F42loco42%2Fcapka","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F42loco42%2Fcapka/lists"}