{"id":15395463,"url":"https://github.com/stef/pitchforkedsphinx","last_synced_at":"2026-01-27T02:02:33.602Z","repository":{"id":66440201,"uuid":"119985753","full_name":"stef/pitchforkedsphinx","owner":"stef","description":"SPHINX based password protocol","archived":false,"fork":false,"pushed_at":"2018-03-06T22:23:45.000Z","size":845,"stargazers_count":7,"open_issues_count":0,"forks_count":1,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-06-01T21:00:46.546Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/stef.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":"2018-02-02T13:35:18.000Z","updated_at":"2023-09-08T17:36:04.000Z","dependencies_parsed_at":"2023-04-18T17:30:43.918Z","dependency_job_id":null,"html_url":"https://github.com/stef/pitchforkedsphinx","commit_stats":{"total_commits":110,"total_committers":2,"mean_commits":55.0,"dds":0.009090909090909038,"last_synced_commit":"d60bc88b215ed02fd6c381d47c7755db0cd7aa9a"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/stef/pitchforkedsphinx","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stef%2Fpitchforkedsphinx","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stef%2Fpitchforkedsphinx/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stef%2Fpitchforkedsphinx/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stef%2Fpitchforkedsphinx/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stef","download_url":"https://codeload.github.com/stef/pitchforkedsphinx/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stef%2Fpitchforkedsphinx/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28796962,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-27T01:07:07.743Z","status":"online","status_checked_at":"2026-01-27T02:00:07.755Z","response_time":168,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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-01T15:28:26.485Z","updated_at":"2026-01-27T02:02:33.588Z","avatar_url":"https://github.com/stef.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# This repo has been discontinued.\n\nIt has exploded in a bunch of git-repos:\n\n - [libsphinx](https://github.com/stef/libsphinx): low-level c library\n - [ed448goldilocks](https://github.com/stef/ed448goldilocks): cross-compile with mingw for windows\n - [pwdsphinx](https://github.com/stef/pwdsphinx/): python-wrapper around libsphinx, including client/server\n - [websphinx-chrom](https://github.com/stef/websphinx-chrom): webextension for chrom/opera\n - [websphinx-firefox](https://github.com/stef/websphinx-firefox): webextension for firefox\n - [winsphinx](https://github.com/stef/winsphinx): build a package on linux for compiling a windows installer on windows\n\n# Readme below and contents of this repo preserved for historical reasons only.\n\nlibdecaf-based sphinx password storage implementation\n\nsphinx: a password *S*tore that *P*erfectly *H*ides from *I*tself\n(*N*o *X*aggeration)\n\npitchforked sphinx is a cryptographic password storage as described in\nhttps://eprint.iacr.org/2015/1099\n\nand as presented by the Levchin Prize winner 2018 Hugo Krawczyk on\nReal World Crypto https://www.youtube.com/watch?v=px8hiyf81iM\n\npitchforked sphinx comes with variety of interfaces: a library, a\npython wrapper around that library, a network server/client written in\npython and simple command-line binaries.\n\n## What is this thing?\n\nIt allows you to have only a few (at least one) passwords that you\nneed to remember, while at the same time provides unique 40 (ASCII)\ncharacter long very random passwords (256 bit entropy). Your master\npassword is encrypted (blinded) and sent to the password storage\nserver which (without decrypting) combines your encrypted password\nwith a big random number and sends this (still encrypted) back to you,\nwhere you can decrypt it (it's a kind of end-to-end encryption of\npasswords) and use the resulting unique, strong and very random\npassword to register/login to various services. The resulting strong\npasswords make offline password cracking attempts infeasible. If say\nyou use this with google and their password database is leaked your\npassword will still be safe.\n\nHow is this different from my password storage which stores the\npasswords in an encrypted database? Most importantly using an\nencrypted database is not \"end-to-end\" encrypted. Your master password\nis used to decrypt the database read out the password and send it back\nto you. This means whoever has your database can try to crack your\nmaster password on it, or can capture your master password while you\ntype or send it over the network. Then all your passwords are\ncompromised. If some attacker compromises your traditional password\nstore it's mostly game over for you. Using sphinx the attacker\ncontrolling your password store learns nothing about your master nor\nyour individual passwords. Also even if your strong password leaks,\nit's unique and cannot be used to login to other sites or services.\n\n## Installing\n\nInstall `libsodium` using your operating system provided package\nmanagement. And if you use any of the python goodies you need to\ninstall also `pysodium` using either your OS package manager or pip.\n\nBuilding everything should be quite simple afterwards:\n\n```\ngit submodule init\nmake\n```\n\n## Library\n\nPitchforked sphinx builds a library, which you can use to build your\nown password manager either in C/C++ or any other language that can\nbind to this library. The library also contains an experimental\nversion of the PKI-free PAKE protocol from page 18 of the paper.\n\nThe Library exposes the following 3 functions for the FK-PTR protocol\n(the password storage):\n\n```\nvoid challenge(const uint8_t *pwd, const size_t p_len, uint8_t *bfac, uint8_t *chal);\n```\n * pwd, p_len: are input params, containing the master password and its length\n * bfac: is an output param, it's a pointer to an array of\n   `DECAF_255_SCALAR_BYTES` (32) bytes - the blinding factor\n * chal: is an output param, it's a pointer to an array of\n   `DECAF_255_SER_BYTES` (32) bytes - the challenge\n\n```\nint respond(const uint8_t *chal, const uint8_t *secret, uint8_t *resp);\n```\n * chal: is an input param, it is the challenge from the challenge()\n   function, it has to be a `DECAF_255_SER_BYTES` (32) bytes big array\n * secret: is an input param, it is the \"secret\" contribution from the\n   device, it is a `DECAF_255_SCALAR_BYTES` (32) bytes long array\n * resp: is an output parameter, it is the result of this step, it\n   must be a `DECAF_255_SER_BYTES` (32) byte sized array\n * the function returns 1 on error, 0 on success\n\n```\nint finish(const uint8_t *bfac, const uint8_t *resp, uint8_t *rwd);\n```\n\n * bfac: is an input param, it is the bfac output from challenge(),\n   it is array of `DECAF_255_SCALAR_BYTES` (32) bytes\n * resp: is an input parameter, it's the response from respond(), it\n   is a `DECAF_255_SER_BYTES` (32) byte sized array\n * rwd: is an output param, the derived (binary) password, it is a\n   `DECAF_255_SER_BYTES` (32) byte array\n * this function returns 1 on error, 0 on success\n\nThe following functions implement the PKI-free PAKE protocol, (for the\nexplanation of the various parameters please see the original paper\nand the pake-test.c example file):\n\n```\nvoid server_init(uint8_t *p_s, uint8_t *P_s);\n```\n\nThis function is called when setting up a new server. It creates a\nlong-term identity keypair. The public key needs to be shared with all\nclients, the secret key needs to be well protected and persisted for\nlater usage.\n\n```\nvoid client_init(const uint8_t *rwd, const size_t rwd_len,\n                 const uint8_t *P_s,\n                 uint8_t k_s[32], uint8_t c[32],\n                 uint8_t C[32], uint8_t P_u[32], uint8_t m_u[32]);\n```\n\nThis function needs to be run on the client when registering at a\nserver. The output parameters need to be sent to the server.\n\n\n```\nvoid start_pake(const uint8_t *rwd, const size_t rwd_len,\n                uint8_t alpha[32], uint8_t x_u[32],\n                uint8_t X_u[32], uint8_t sp[32]);\n```\n\nThe client initiates a \"login\" to the server with this function.\n\n```\nint server_pake(const uint8_t alpha[32], const uint8_t X_u[32],  // input params\n                const uint8_t k_s[32], const uint8_t P_u[32],\n                const uint8_t p_s[32],\n                uint8_t beta[32], uint8_t X_s[32],               // output params\n                uint8_t SK[DECAF_X25519_PUBLIC_BYTES]);\n```\n\nThis function implements the \"login\" on the server, it reuses the data\nreceived when registering the user, and some other parameters that\ncame out of start_pake() when the client initiated the \"login\". At\nsuccessful completion SK should be a shared secret with the client. On\nerror the function return 1, otherwise 0.\n\n```\nint user_pake(const uint8_t *rwd, const size_t rwd_len, const uint8_t sp[32],\n              const uint8_t x_u[32], const uint8_t beta[32], const uint8_t c[32],\n              const uint8_t C[32], const uint8_t P_u[32], const uint8_t m_u[32],\n              const uint8_t P_s[32], const uint8_t X_s[32],\n              uint8_t SK[DECAF_X25519_PUBLIC_BYTES]);\n```\n\nThis function finalizes the \"login\" on the client side. At successful\ncompletion SK should be a shared secret with the server. On error the\nfunction return 1, otherwise 0.\n\n## Standalone Binaries\n\npitchforked sphinx comes with very simple binaries, so you can build\nyour own password storage even from shell scripts. Each step in the\nprotocol is handled by one binary:\n\n### step 1 - challenge\nThe following creates a challenge for a device:\n```\necho -n \"shitty master password\" | ./challenge \u003ec 2\u003eb\n```\nThe master password is passed in through standard input.\n\nThe challenge is sent to standard output.\n\nA blinding factor is stored in a tempfile, the name of this file is output to\nstderr. This tempfile is needed in the last step again.\n\n### step 2 - device responds\nPass the challenge from step 1 on standard input like:\n```\n./respond secret \u003cc \u003er0\n```\nThe response is sent to standard output.\n\n### step 3 - derive password\nTo derive a (currently hex) password, pass the response from step 2 on standard\ninput and the filename of the tempfile from step 1 like:\n```\nfname=$(cat b)\n./derive $fname \u003cr0 \u003epwd0\n```\nThe derived password is sent to standard output and currently is a 32 byte\nbinary string.\n\n### step 4 - transform into ASCII password\nThe output from step 3 is a 32 byte binary string, most passwords have some\nlimitations to accept only printable - ASCII - chars. `bin2pass.py` is a python\nscript which takes a binary input on standard input and transforms it into an\nASCII password. It can have max two parameters the classes of characters\nallowed ([*u*]pper-, [*l*]ower-case letters, [*d*]igits and [*s*]ymbols) and\nthe size of the password. The following examples should make this clear:\n\nFull ASCII, max size:\n```\n./bin2pass.py \u003cpwd0\n```\nno symbols, max size:\n```\n./bin2pass.py uld \u003cpwd0\n```\nno symbols, 8 chars:\n```\n./bin2pass.py uld 8 \u003cpwd0\n```\nonly digits, 4 chars:\n```\n./bin2pass.py d 4 \u003cpwd0\n```\nonly letters, 16 chars:\n```\n./bin2pass.py ul 16 \u003cpwd0\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstef%2Fpitchforkedsphinx","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstef%2Fpitchforkedsphinx","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstef%2Fpitchforkedsphinx/lists"}