{"id":15395457,"url":"https://github.com/stef/pwdsphinx","last_synced_at":"2025-04-16T00:10:24.597Z","repository":{"id":30221766,"uuid":"123977264","full_name":"stef/pwdsphinx","owner":"stef","description":"a reference client/server and a native backend for web-extensions for Sphinx-based password storage","archived":false,"fork":false,"pushed_at":"2025-03-31T23:49:05.000Z","size":1443,"stargazers_count":22,"open_issues_count":3,"forks_count":10,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-04-16T00:09:48.278Z","etag":null,"topics":["client-server","password-manager","password-storage","python","python-bindings","sphinx","web-extension","x11-utilities"],"latest_commit_sha":null,"homepage":"https://www.ctrlc.hu/~stef/blog/posts/sphinx.html","language":"Python","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-03-05T20:51:28.000Z","updated_at":"2025-04-07T23:06:04.000Z","dependencies_parsed_at":"2024-06-08T18:12:41.640Z","dependency_job_id":null,"html_url":"https://github.com/stef/pwdsphinx","commit_stats":{"total_commits":374,"total_committers":8,"mean_commits":46.75,"dds":0.0401069518716578,"last_synced_commit":"1ce712095ac3cc931c995388e151e5f6c9057eba"},"previous_names":[],"tags_count":32,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stef%2Fpwdsphinx","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stef%2Fpwdsphinx/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stef%2Fpwdsphinx/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stef%2Fpwdsphinx/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stef","download_url":"https://codeload.github.com/stef/pwdsphinx/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249173086,"owners_count":21224483,"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":["client-server","password-manager","password-storage","python","python-bindings","sphinx","web-extension","x11-utilities"],"created_at":"2024-10-01T15:28:25.362Z","updated_at":"2025-04-16T00:10:24.589Z","avatar_url":"https://github.com/stef.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!--\nSPDX-FileCopyrightText: 2018, Marsiske Stefan\n\nSPDX-License-Identifier: CC-BY-SA-4.0\n--\u003e\n\nsphinx: a password **S**tore that **P**erfectly **H**ides from **I**tself (**N**o **X**aggeration)\n\npwdsphinx is python wrapper around libsphinx - a cryptographic password storage\nas described in https://eprint.iacr.org/2015/1099\n\n## Also on Radicle\n\nTo clone this repo on [Radicle](https://radicle.xyz), simply run:\n\n  `rad clone rad:z3rjK2hk7ckb1thexdsuyaM7e4FwS`\n\n## Dependencies\n\nYou need [liboprf](https://github.com/stef/liboprf) and [libequihash](https://github.com/stef/equihash/) for the python reference frontend.\n\nYou need also to install `pysodium` and `pyoprf` using either\nyour OS package manager or pip.\n\nIf you want to use also the websphinx browser extension you need to\ninstall also an X11 variant of pinentry from the gnupg project:\n\n - either `apt-get install pinentry-qt`\n - or `apt-get install pinentry-gtk2`\n - or `apt-get install pinentry-gnome3`\n - or `apt-get install pinentry-fltk`\n\n(or anything equivalent to `apt-get install` on your OS)\n\nIf you want to store other \"secrets\" that are longer than just 30-40 bytes, you\ncan install opaque-store: https://github.com/stef/opaque-store/ using\n\n  `pip3 install opaquestore`\n\nwhich depends additionally on libopaque: https://github.com/stef/libopaque\n\n## Installation\n\n`pip3 install pwdsphinx` should get you started.\n\n## Server/Client\n\nSince the SPHINX protocol only makes sense if the \"device\" is\nsomewhere else than where you type your password, pwdsphinx\ncomes with a server implemented in python3 which you can host off-site\nfrom your usual desktop/smartphone. Also a client is supplied which is\nable to communicate with the server and manage passwords.\n\nBoth the client and the server can be configured by any of the\nfollowing files:\n\n - `/etc/sphinx/config`\n - `~/.sphinxrc`\n - `~/.config/sphinx/config`\n - `./sphinx.cfg`\n\nFiles are parsed in this order, this means global settings can be\noverridden by per-user and per-directory settings.\n\n### oracle - the server\n\npwdsphinx comes with a python reference implementation of a extended sphinx\nserver called oracle.\n\nThe server can be \"configured\" by changing the variables in the\n`[server]` section of the config file.\n\nThe `address` is the IP address on which the server is listening,\ndefault is `localhost` - you might want to change that.\n\nThe `port` where the server is listening is by default 2355.\n\n`datadir` specifies the data directory where all the device \"secrets\"\nare stored, this defaults to \"data/\" in the current directory. You\nmight want to back up this directory from time to time to an encrypted\nmedium.\n\n`verbose` enables logging to standard output.\n\n`timeout` sets the timeout for any connection the server keeps open.\n\n`max_kids` sets the number maximum requests handled in parallel. The\n`timeout` config variable makes sure that all handlers are recycled in\npredictable time.\n\n`rl_decay` specifies the number of seconds after which a ratelimit level\ndecays to an easier difficulty.\n\n`rl_threshold` increase the difficulty of ratelimit puzzles if not\ndecaying.\n\n`rl_gracetime` gracetime in seconds added to the expcted time to solve\na rate-limiting puzzle.\n\nChange these settings to fit your needs. Starting the server\ncan be done simply by:\n\n```\noracle\n```\n\nFor more information see the man-page `oracle(1)`\n\n### sphinx - the client\n\nThis is the client that connects to the oracle to manage passwords\nusing the extended sphinx protocol.\n\n#### Client Configuration\n\nThe client can be configured changing the settings in the `[client]`\nsection of the config file.\n\nThe datadir (default: `~/.sphinx`) variable holds the location for your client\nparameters. Particularly it contains a masterkey which is used to derive\nsecrets. The master key - if not available - is generated by issuing an init\ncommand. You **should** back up and encrypt this master key.\n\n`rwd_keys` toggles if the master password is required for\nauthentication of management operations. If it is False it protects\nagainst offline master password bruteforce attacks - which is also a\nsecurity guarantee of the original SPHINX protocol. The drawback is\nthat for known (host,username) tuples the seeds/blobs can be\nchanged/deleted by an attacker if the clients masterkey is available\nto them. But neither the master nor the account password can leak this\nway. This is merely a denial-of-service vector. If rwd_keys is True,\nthen this eliminates the denial-of-service vector, but instead\neliminates the offline-bruteforce guarantee of the SPHINX\nprotocol. Note that the oracle is oblivious to this setting, this is\npurely a client-side toggle, in theory it is possible to have\ndifferent settings for different \"records\" on the oracle.\n\n`validate_password` Stores a check digit of 5 bits in on the oracle,\nthis helps to notice most typos of the master password, while\ndecreasing security slightly.\n\n`userlist` option (default: True) can disable the usage of userlists. This\nprohibits the server to correlate all the records that belong to the same\nsphinx user relating to the same host. The cost of this, is that the user has\nto remember themselves which usernames they have at which host.\n\nFor more detailed information consult the man-page `sphinx(1)`\n\n#### Operations\n\nThe client provides the following operations: Create, Get, Change, Commit,\nUndo, List and Delete. All operations need a username and a site this\npassword belongs to, even if they're only empty strings.\n\n#### Create password\n\nCreating a new password for a site is easy, pass your \"master\"\npassword on standard input to the client, and provide parameters like\nin this example:\n\n```\necho -n 'my master password' | sphinx create username example.com ulsd 0 ' !\"#$%\u0026\\'()*+,-./:;\u003c=\u003e?@[\\\\]^_`{|}~'\n```\n\nThe parameters to the client are `create` for the operation, then `username`\nfor the username on the site `example.com` then a combination of the\nletters `ulsd` and the `0` for the size of the final password. The letters\n`ulsd` stand in order for the following character classes: `u` upper-case\nletters, `l` lower-case letters, `s` symbols and `d` for digits. The `s` is a\nshort-cut to allow all of the symbols, if you have a stupid server that limits\nsome symbols, you can specify the allowed symbols explicitly. Currently these\nare the symbols supported (note the leading space char):\n\n```\n !\"#$%\u0026'()*+,-./:;\u003c=\u003e?@[\\]^_`{|}~\n```\n\nBe careful, if you specify these on the command-line you'll have to\nescape the quotes you use for enclosing this list and possibly the\nbackslash char that is also part of this list. In the `create\nusername` example above the symbols are correctly escaped, in case you\nneed to copy/paste them.\n\nIf you do not provide password rules, they will be defaulting to 'ulsd' and\nlength as long as possible.\n\nIf the command runs successfully - the resulting new high-entropy password\naccording to the given rules is printed to the console.\n\nIn case for some reason you cannot use random passwords with your\naccount, or you want to store a \"password\" that you cannot change,\nlike a PIN code for example, or a passphrase shared with your\ncolleagues, you can specify a maximum 44 character long password, that\nwill be generated by the SPHINX client for you. In that case the\ncommand line looks like this (note the same syntax also works for the\n`change` operation)\n\n```\necho -n 'my master password' | sphinx create username example.com \"correct_battery-horse#staple\"\n```\n\nIn this case you cannot specify neither the accepted character\nclasses, nor the size, nor symbols.\n\nNote1, since the master password is not used to encrypt anything, you can\nactually use different \"master\" passwords for different user/site combinations.\n\nNote2, using echo is only for demonstration, you should use something like this\ninstead (getpwd is available from the contrib directory):\n```\ngetpwd.sh | sphinx create username example.com ulsd 0\n```\n\n#### Get password\n\nGetting a password from the sphinx oracle works by running the\nfollowing command:\n\n```\necho -n 'my master password' | sphinx get username example.com\n```\n\nHere again you supply your master password on standard input, provide\nthe `get` operation as the first parameter, your `username` as the 2nd\nand the `site` as the 3rd parameter. The resulting password is\nreturned on standard output.\n\n#### Change password\n\nYou might want to (or are forced to regularly) change your password, this\nis easy while you can keep your master password the unchanged (or you\ncan change it too, if you want). The command is this:\n\n```\necho -en 'my master password\\nnew masterpassword' | sphinx change username example.com 'ulsd' 0 ' !\"#$%\u0026\\'()*+,-./:;\u003c=\u003e?@[\\\\]^_`{|}~'\n```\n\nHere again you supply your master password on standard input, but\nseparated by a new-line you also provide the new master password. The\nnew master password can be the same as the old, but can also be a new\npassword if you want to change also the master password. You provide\nthe `change` operation as the first parameter to the client, your\n`username` as the 2nd and the `site` as the 3rd parameter.  You also\ncan provide similar password generation rule parameters that were also\nused to create the original password, in case your account has new\npassword rules and you want/have to accommodate them. Your new\npassword is returned on standard output.\n\n#### Committing a changed password\n\nAfter changing the password, you will still get the old password when running\n`get`. To switch to use the new password you have to commit the changes with\n\n```\necho -n 'my master password' | sphinx commit username example.com\n```\n\n#### Undoing a password commit\n\nIf you somehow messed up and have to go back to use the old password, you can\nundo committing your password using:\n\n```\necho -n 'my master password' | sphinx undo username example.com\n```\n\n#### Deleting passwords\n\nIn case you want to delete a password, you can do using the following\ncommand:\n\n```\necho -n \"my master password\" | sphinx delete username example.com\n```\n\nYou provide the `delete` operation as the first parameter to the\nclient, your `username` as the 2nd and the `site` as the 3rd\nparameter. This command does not provide anything on standard output\nin case everything goes well.\n\n#### QR code config\n\nIn case you want to use phone with the same sphinx server, you need to export\nyour config to the phone via a QR code.\n\n```\nsphinx qr\n```\n\nWill display a QR code containing only public information - like the server\nhost and port, and if you use rwd_keys. This is mostly useful if you want to\nshare your setup with a friend or family.\n\nIf you want to connect your own phone to the setup used with pwdsphinx, you\nalso need to export your client secret in the QR code:\n\n```\nsphinx qr key\n```\n\nThis contains your client secret, and you should keep this QR code\nconfidential. Make sure there is no cameras making copies of this while this QR\ncode is displayed on your screen.\n\nIf for whatever reason you want to display the QR code as an SVG, just append\nthe `svg` keyword to the end of the `sphinx qr` command.\n\n## OPAQUE-Store client-integration\n\nIf you have opaque-store installed and configured correctly you get a number of\nadditional operations, which allow you to store traditionally encrypted blobs\nof information. For a gentle introduction how this works using OPAQUE, have a\nlook at this post:\n\n`https://www.ctrlc.hu/~stef/blog/posts/How_to_recover_static_secrets_using_OPAQUE.html`\n\nThe following operations will be available if opaque-store is setup correctly:\n\n```sh\necho -n 'password' | sphinx store \u003ckeyid\u003e file-to-store\necho -n 'password' | sphinx read \u003ckeyid\u003e\necho -n 'password' | sphinx replace [force] \u003ckeyid\u003e file-to-store\necho -n 'password' | sphinx edit [force] \u003ckeyid\u003e\necho -n 'password' | sphinx changepwd [force] \u003ckeyid\u003e\necho -n 'password' | sphinx erase [force] \u003ckeyid\u003e\necho -n 'password' | sphinx recovery-tokens \u003ckeyid\u003e\necho -n 'password' | sphinx unlock \u003ckeyid\u003e \u003crecovery-token\u003e\n```\n\n### How does OPAQUE-Store SPHINX integration work\n\nIn all OPAQUE-Store operations we first execute a SPHINX get\noperation, that calculates the password which is used with\nOPAQUE. This means that the input passwords for OPAQUE will be the\nstrongest possible and essentially un-bruteforcable on their own\n(without SPHINX). Of course online bruteforce attacks are still\npossible going through SPHINX. But OPAQUE is able to detect wrong\npasswords and thus can lock your record after a pre-configured amount\nof failed attempts. Of course this does not apply to the operator of\nan OPAQUE server, who can circumvent the locking of records. And thus:\n\n### A Warning: don't let one entity control your SPHINX and OPAQUE-Store servers\n\nAs you can see every opaque-store op needs a password on standard\ninput. This password is run through SPHINX, and the output password is\nused in the OPAQUE protocol as the input password. This also means,\nthat if you use a single server setup for both SPHINX and\nOPAQUE-Store, the two servers should not be controlled by the same\nentity, otherwise this entity is able to offline-bruteforce your\nSPHINX master password. If you use either of these services in a\nthreshold setup, and these threshold servers are controlled by\ndifferent entities, you should be ok, as long as no one controls a\nthreshold number of oracles/servers.\n\n### OPAQUE-Store CLI Parameters\n\n#### KeyId\n\nEvery operation provided by the OPAQUE-Storage (O-S) integration needs\na \"keyid\" parameter, this references your record stored by\nO-S. Internally the client uses the configuration value `id_salt`,\ntogether with the name of the O-S server to hash the keyid parameter\ninto a record id for the O-S Server. This means, that if you lose or\nchange your `id_salt` parameter or the name of the O-S server, all\nyour record ids will be different and inaccessible. So it is a good\nidea to make a backup of your configuration file containing these.\n\n#### Forced operations\n\nIn the case that you are using a threshold setup, some operations\n(`replace`, `edit`, `changepwd` and `erase`) require that all servers\nsuccessfully participate in the operation. This is to avoid, that the\nrecords on temporarily unavailable servers remain unchanged and lead\nlater possibly to corruption. If you are sure however that this is ok,\nyou can provide a `force` parameter on the CLI which reduces the\nnumber of servers successfully participating to the value of your\n`threshold` configuration setting.\n\n### Store an encrypted blob\n\n```sh\ngetpwd | sphinx store \u003ckeyid\u003e file-to-store\n```\n\nThis simply does what it promises, stores the `file-to-store`\nencrypted on the OPAQUE-Store server, using a password derived from\nSPHINX. Note that this command outputs also a recovery-token, which\nyou should keep safe in case your record gets locked.\n\n### Retrieving an encrypted blob\n\n```sh\ngetpwd | sphinx read \u003ckeyid\u003e\n```\n\nStraightforward, no surprise.\n\n### Overwrite an encrypted blob\n\n```sh\ngetpwd | sphinx replace [force] \u003ckeyid\u003e file-to-store\n```\n\nWhatever has been stored at `keyid` is now overwritten by an encrypted\n`file-to-store`. This only works, if there is already something stored\nat `keyid`. All servers must cooperate in this, if one or more are\nunavailable this will fail, unless `force` is specified and the\nthreshold is matched, in which case the servers unavailable will be\ncorrupted from this point on.\n\n### Edit a file\n\n```sh\ngetpwd | sphinx edit [force] \u003ckeyid\u003e\n```\n\nThis operation fetches the file stored at `keyid` loads it into your\neditor (specified by the `EDITOR` environment variable) and stores the\nchanges and saved file back on the same `keyid` overwriting the\noriginal.\n\n### Change your password\n\n```sh\ngetpwd | sphinx changepwd [force] \u003ckeyid\u003e\n```\n\nThis operation does a full change of passwords and keys. Even if you\ndon't change your own password that you provide to getpwd, SPHINX will\nchange it's own key, and thus change the output password which will be\nused for the password in OPAQUE-store finally resulting in a whole new\nand fresh encryption key for your file which gets re-encrypted with\nthat.\n\n### Delete a stored file\n\n```sh\ngetpwd | sphinx erase [force] \u003ckeyid\u003e\n```\n\nNothing surprising here, does what is written on the package.\n\n### Get a recovery token\n\n```sh\ngetpwd | sphinx recovery-tokens \u003ckeyid\u003e\n```\n\nIf your record is not locked, this operation gets you an additional\nrecovery token, that you can use later to unlock your record, should\nit become locked.\n\n### Unlock a locked record\n\n```sh\ngetpwd | sphinx unlock \u003ckeyid\u003e \u003crecovery-token\u003e\n```\n\nIf for some reason (someone online-bruteforcing your record, or you\nforgetting your master password) your record becomes locked by the\nservers, you can unlock it using a recovery token.\n\n## X11 frontend\n\nYou can find a bunch of shell-scripts that are based on\n`pinentry-(gtk|qt)`, `xinput`, `xdotool` and `dmenu`, the top-level\nentry to these is the `dmenu-sphinx.sh` script, which stores its\nhistory of entered hostnames in `~/.sphinx-hosts` - if the hosts are\nin any way sensitive, you might want to link this file to\n`/dev/null`. The `contrib/README.md` should give you an idea of how\nelse to combine these scripts.\n\n## Credits\n\nThis project was funded through the NGI0 PET Fund, a fund established\nby NLnet with financial support from the European Commission's Next\nGeneration Internet programme, under the aegis of DG Communications\nNetworks, Content and Technology under grant agreement No 825310.\n\nThis project was funded through the e-Commons Fund, a fund established by NLnet\nwith financial support from the Netherlands Ministry of the Interior and\nKingdom Relations.\n\nEverlasting gratuity to asciimoo, dnet, jonathan and hugo for their\ncontributions, patience, and support.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstef%2Fpwdsphinx","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstef%2Fpwdsphinx","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstef%2Fpwdsphinx/lists"}