sphinx(1)
π sphinx(1) β the command-line client for the SPHINX password manager π
okay so bestie, this is sphinx, the command-line client for the SPHINX password manager, and honestly? she's giving cryptography royalty π. Grab a snack π, because we're walking through the entire lifecycle of a password together and I am not letting you skip a single flag.
β¨ SYNOPSIS β¨
sphinx init
echo βpasswordβ | sphinx create <user> <site> [<u><l><d><s>] [<size>] [<symbols>] [<target password>]
echo βpasswordβ | sphinx get <user> <site>
echo -e βoldpasswordβ | sphinx change <user> <site> [<u><l><d><s>] [<size>] [<symbols>] [<target password>]
[ echo βpasswordβ | ] sphinx commit <user> <site>
[ echo βpasswordβ | ] sphinx undo <user> <site>
[ echo βpasswordβ | ] sphinx delete <user> <site>
sphinx list <site>
sphinx healthcheck
sphinx qr [<svg>] [<key>]
Here's the general vibe, and it's lowkey the most important rule of the whole page: if an operation needs a master (input) password, it expects it on standard input, and any resulting account (output) password gets printed to standard output. π
The examples below use echo, but for real life the recommendation is to use getpwd(1) or similar tools to query and pass the input password. (Because echo is a snitch, no cap. π)
π¦ DESCRIPTION π¦
SPHINX stands for password Store that Perfectly Hides from Itself (No Xaggeration) β obsessed with that name fr fr. It's an information-theoretically secure cryptographic password storage protocol with strong security guarantees. π
The protocol is described in the 2015 paper βDevice-Enhanced Password Protocols with Optimal Online-Offline Protectionβ by Jarecki, Krawczyk, Shirvanian, and Saxena (https://ia.cr/2015/1099). Go read it, it ate. π₯
πΈ OPERATIONS πΈ
sphinx is the command-line client for the SPHINX protocol. It gives you access to all the operations over the lifecycle of a password: init, create, get, change, undo, commit, delete, and list. β¨
Every single one of those operations requires a username and a site that the password belongs to β even if they're just empty strings. Yes bestie, even then. π
On top of that, it also provides operations that make these features more user-friendly: listing of users associated with a host, and export of the configuration using a QR code. π
And she's multidimensional β sphinx doesn't only handle passwords, it also handles Time-based One-Time Password (TOTP) Two-Factor Authentication (2FA) and age keys. π
Additionally, if installed, sphinx also provides access to OPAQUE-Store, a simple tool that allows one to store secrets that need encrypted storage (like keys, phrases, or other data). Slay.
π§ INITIALIZING A CLIENT
sphinx init
This creates a new masterkey for the client, which is used to address records on the SPHINX server and authorize management operations on those records. π
You SHOULD back up and encrypt this masterkey. Like, please. π
If you want to use SPHINX on a different device, you want to copy this masterkey there as well. For copying this key (and other settings) to the Android client, androsphinx, see the qr operation below. π±
This init operation also creates a fixed healthcheck record on the server(s), as described in the HEALTHCHECK section below. π©Ί
Additionally, if ~/.mozilla or ~/.config/chromium directories are found, the init command will automatically set up the web extensions for Firefox and Chromium-based browsers respectively. She's proactive like that. π
π CREATE PASSWORD
To create a new password for a site, provide your master password via standard input to the client, along with the required parameters. For example:
echo -n 'my input password' | sphinx create username example.com ulsd 0 ' !"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'
The parameters are:
- Master password on standard input: Unlike traditional password managers that use a single master password for the entire database, you can use different input passwords for different username/site combinations. Main character energy, honestly. β¨
create: Specifies the operation type.username: Your username for the site.example.com: The target site.- Password constraints: Rules for generating the password. See sections PASSWORD RULES and PREDETERMINED PASSWORDS for more info.
If the command runs successfully, the resulting new high-entropy output password, generated according to the given rules, is printed to the console. π«Ά
π GET PASSWORD
To retrieve a stored password from the SPHINX oracle, run:
echo -n 'my master password' | sphinx get username example.com
You provide your master password via standard input, followed by:
get: Specifies the operation.username: Your username.example.com: The site.
The corresponding password is printed to standard output. π
π₯ CHANGE PASSWORD
If you need to change a password (whether the site required it or you just felt like it π ), you can do so without changing your master password β although you may change both if desired. For example:
echo -en 'my master password\nnew masterpassword' | sphinx change username example.com 'ulsd' 0 ' !"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'
The parameters are:
- On standard input, provide your current master password, followed by a newline, then your new master password. The new master password can be identical to the old one if you only want to update the site password. π―
change: Specifies the operation.username: Your username.example.com: The site.- Password generation rules: Same format as when creating the original password. Adjust these if the site now requires different constraints (see PASSWORD RULES and PREDETERMINED PASSWORDS).
The newly generated password will be printed to standard output.
IMPORTANT: This command only generates the new password β it does not activate it. Thegetcommand will still return your old password until you run acommitoperation to make the change effective. See the next section for details. π (don't say I didn't warn you)
β COMMITTING A CHANGED PASSWORD
After changing a password, the get operation will still return the old password. To start using the new password, you must commit the change by running:
echo -n 'my master password' | sphinx commit username example.com
Depending on your rwd_keys configuration (explained in the SECURITY CONSIDERATIONS section below), you may need to provide your input password on standard input for this operation. π
If the operation is successful, there will be no output. If an error occurs, an error message will be displayed and the command will exit with a non-zero status code. π
π UNDOING A PASSWORD COMMIT
If you need to revert to the old password after committing a new one, run:
echo -n 'my master password' | sphinx undo username example.com
Depending on your rwd_keys configuration, you may need to provide your master password on standard input for this operation.
If successful, there will be no output. Otherwise, an error message and a non-zero exit code will indicate a problem. π
π¦ DELETING PASSWORDS
To delete a password, use the following command:
echo -n "my master password" | sphinx delete username example.com
Here:
deletespecifies the operation.usernameis your account name.example.comis the target site.
If the operation succeeds, there will be no output. If it fails, you will see an error message and a non-zero exit code. Depending on your rwd_keys configuration, you may need to provide your master password via standard input. π
π± QR CODE CONFIG
If you want to use your phone with the same SPHINX server, you can export your configuration to the phone using a QR code.
sphinx qr
This displays a QR code containing configuration information from your [servers] section and client settings such as userlist, validate_password, delete_upgraded, and threshold. This is useful for sharing your setup with trusted friends or family. π«Ά
To connect your own phone to the setup used with pwdsphinx, include your client secret in the QR code:
sphinx qr key
This QR code contains sensitive information, so keep it private and ensure no cameras can capture it while it's displayed. π no screenshots bestie
To display the QR code as an SVG instead of text, append the svg keyword to the sphinx qr command:
sphinx qr svg
π©Ί HEALTHCHECK
If you have run the sphinx init command, it has created a fixed healthcheck record. You can verify your setup by running:
sphinx healthcheck
This checks connectivity to the server without affecting rate limits. β¨
Alternatively, you can test with a get operation:
echo -n 'all ok?' | env/bin/sphinx get healthcheck "sphinx servers"
This should output βeverything works fineβ.
The difference is that healthcheck only fetches rate-limiting challenges and then stops, while get will count against your rate limit if used too frequently. So like, use the right one. π
π PASSWORD RULES
When creating or changing passwords, you can specify rules limiting the size and characters allowed in the output password.
The letters u, l, s, and d represent the following character classes:
u: Upper-case lettersl: Lower-case letterss: Symbolsd: Digits
The s shortcut includes all supported symbols. If you are limited by the server to specific symbols, you can explicitly specify them.
Supported symbols (note the leading space character π) are:
!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
When using these symbols on the command line, be sure to escape quotes and possibly the backslash character. In the create username example above, symbols are correctly escaped for copy/paste. π«Ά
For examples, see the sections CREATE PASSWORD and CHANGE PASSWORD.
β DEFAULT RULES
If you do not specify password rules, they will default to ulsd with the maximum possible length of 77 characters. This means passwords will use all four character classes, providing 507 bits of entropy. This is far more than necessary for most use cases. π₯
π RECOMMENDED OUTPUT PASSWORD LENGTH
When using the ulsd character classes, it is recommended to limit the output password length to a maximum of 12 characters. This is especially useful if you ever need to type the password on a TV remote or in other stressful situations. π (the way that TV keyboards are a personal attack)
A 12-character password with full entropy using all printable ASCII characters offers almost 80 bits of entropy, making it computationally impossible to brute force with current password-cracking hardware. For comparison, a 15-character password offers nearly 99 bits of entropy. π
πΈ PREDETERMINED OUTPUT PASSWORDS
If you cannot use random passwords for your account, or if you need to store a fixed βpasswordβ such as a PIN code or a shared passphrase, you can set a predetermined password (up to 77 characters). The SPHINX client will generate it for you. β¨
For example, the command below (which also works for the change operation) sets a fixed password:
echo -n 'my master password' | sphinx create username example.com "correct_battery-horse#staple"
In this case, you cannot specify character classes, size, or symbols. These values will be inferred from the predetermined password itself. π¦
πΎ Backward compatibility with v1 SPHINX servers/records πΎ
okay so bestie, if you've still got old v1 SPHINX records sitting on the server that were made back in the v1 era and you actually wanna keep using them?? you gotta specify that server in the client section exactly like you did in v1. no shortcuts, no vibes-only approach.
Here's the cute part tho: if no v2 record turns up during a get operation, SPHINX will automatically go looking for a v1-style record. And if it finds one? It just makes a brand-new v2 record for you on the spot β¨. So you literally do not need to manually go hunting for v1 records in that situation. it's giving self-care automation.
Now, if you're not using other v1-only clients (hi androsphinx π), those upgraded v1 records can get automatically deleted after a successful migration over to v2. To turn that on, set delete_upgraded to true in the [client] section of your SPHINX configuration. This keeps your server database all clean and sparkly π§Ό and makes it super easy to track how many v1 records are still hanging around.
β¨ OUTPUT PLUGINS (TOTP & AGE) β¨
SPHINX can also "store" TOTP secrets and age secret keys π. And when you store a secret like that, SPHINX automatically handles it the right way (like, outputting the TOTP verification code instead of the secret itself). Obsessed.
To make this happen, prefix your username with otp:// for TOTP support, or age:// for age key support. And for age keys specifically, the query will return a properly formatted private key. no cap.
Currently, the following converters are supported:
π’ TOTP π’
Import a TOTP secret:
% getpwd | sphinx create otp://username example.com ABCDEF1234567890
Get a TOTP PIN:
% getpwd | sphinx get otp://username example.com
βοΈ minisign βοΈ
Create a new key and store the public key at /tmp/minisig.pub:
% getpwd \
| sphinx create minisig://user example.com >/tmp/minisig.pub
Create and Change SPHINX operations automatically return a public key. π
Sign a file filetosign:
% getpwd \
| sphinx get minisig://user example.com \
| pipe2tmpfile minisign -S -s @@keyfile@@ -m filetosign
The Get SPHINX operation returns a private key. π
𧬠Age π§¬
Generate an age key and store the public key:
% getpwd \
| sphinx create age://user example.com >/tmp/age.pub
Create and Change SPHINX operations automatically return a public key.
Decrypt a file using an age key from SPHINX:
% getpwd \
| sphinx get age://user localhost \
| pipe2tmpfile age --decrypt -i @@keyfile@@ encryptedfile
The Get SPHINX operation returns a private key.
π¦ SSH-ED25519 π¦
Create a key and save the public key:
% getpwd \
| sphinx create ssh-ed25519://test asdf >pubkey
Create and Change SPHINX operations automatically return a public key.
Sign a file:
% getpwd \
| sphinx get ssh-ed25519://test asdf \
| pipe2tmpfile ssh-keygen -Y sign -n file -f @@keyfile@@ content.txt > content.txt.sig
The Get SPHINX operation returns a private key.
Verify a file with a public key:
% ssh-keygen -Y check-novalidate -n file -f /tmp/ssh-ed.pubkey -s /tmp/content.txt.sig </tmp/content.txt
π OPAQUE-Store INTEGRATION π
If you have OPAQUE-Store installed and configured correctly (see GitHub for that, and also see opaque-stored.cfg(5)), you unlock a whole extra set of commands that let you store encrypted blobs of data π«Ά. These commands only show up if OPAQUE-Store is properly set up, jsyk:
echo -n 'password' | sphinx store <keyid> file-to-store
echo -n 'password' | sphinx read <keyid>
echo -n 'password' | sphinx replace [force] <keyid> file-to-store
echo -n 'password' | sphinx edit [force] <keyid>
echo -n 'password' | sphinx changepwd [force] <keyid>
echo -n 'password' | sphinx erase [force] <keyid>
echo -n 'password' | sphinx recovery-tokens <keyid>
echo -n 'password' | sphinx unlock <keyid> <recovery-token>
π€ How does OPAQUE-Store SPHINX integration work
In all OPAQUE-Store commands, a SPHINX get operation runs first. This generates the password used with OPAQUE, which means the OPAQUE password ends up extremely strong and nearly impossible to brute-force unless somebody goes through SPHINX. slay, security-wise.
BUT β online brute-force attempts via SPHINX are still possible π. OPAQUE can detect invalid passwords and lock records after a configured number of failed attempts. Just know that this lock does not apply to the operator of an OPAQUE server, who could bypass it. π
β οΈ A WARNING: Don't let one entity control enough of your SPHINX and OPAQUE-Store servers β οΈ
Every OPAQUE-Store operation requires a password via standard input. That password gets run through SPHINX, and the output password is then used in the OPAQUE protocol as the input password.
So if both SPHINX and OPAQUE-Store are hosted on the same server, or controlled by the same third party, they could potentially perform an offline brute-force attack against your SPHINX master password. π If you use a threshold setup where different entities control the servers, you stay secure as long as no single entity controls enough servers to meet the threshold. That's the whole point fr fr.
π§Ύ OPAQUE-Store CLI Parameters π§Ύ
KeyId β every OPAQUE-Store integration command needs a keyid parameter, which references your stored record. The client uses the id_salt configuration value together with the OPAQUE-Store server's name to hash the keyid into a record ID. So if you lose or change either id_salt or the server name, your record IDs will change and your data becomes inaccessible π. Back up your configuration file so this never happens to you. And while id_salt doesn't need to be secret, keeping it private adds an extra layer of security. π
Forced operations β in threshold setups, certain commands (replace, edit, changepwd, and erase) require that all servers participate successfully in the operation. Why? To avoid situations where some servers become out of sync (corrupted) from the others π. If you're certain it's safe, you can add the force flag to let the operation succeed with only the minimum number of servers specified by your threshold setting.
π¦ Store an encrypted blob
getpwd | sphinx store <keyid> file-to-store
Stores the specified file-to-store in encrypted form on the OPAQUE-Store server, using a password derived from SPHINX.
Heads up bestie: this command also outputs a recovery token, and you should keep that safe in case the record is ever locked. Don't lose it!! π
π€ Retrieve an encrypted OPAQUE-Store blob
getpwd | sphinx read <keyid>
Retrieves the record stored at keyid and outputs it to standard output.
β»οΈ Overwrite an encrypted OPAQUE-Store blob
getpwd | sphinx replace [force] <keyid> file-to-store
Replaces the record stored at keyid with an encrypted version of file-to-store. This command only works if a record already exists at keyid, so don't come at it empty-handed.
By default, all servers must participate successfully. If some are unavailable, you can use force to proceed as long as the threshold is met β but just know that unavailable servers will become out of sync (corrupted) from this point on. π you've been warned.
π Edit an OPAQUE-Store blob
getpwd | sphinx edit [force] <keyid>
This operation fetches the file stored at keyid, opens it in your default editor (specified by the EDITOR environment variable), and stores the saved changes back at the same keyid, overwriting the original. Very main character of it ngl.
π Change your password on an OPAQUE-Store blob
getpwd | sphinx changepwd [force] <keyid>
This operation rotates all passwords and keys for the record at keyid. And here's the fun bit: even if your own password (the one you supplied to getpwd) stays exactly the same, SPHINX will generate a new key, which in turn produces a new OPAQUE password. That gives you a completely new encryption key for your file, and the file gets re-encrypted with it. glow up π₯
ποΈ Delete a stored OPAQUE-Store blob
getpwd | sphinx erase [force] <keyid>
Deletes the record stored at keyid. gone, periodt.
ποΈ Get a recovery token
getpwd | sphinx recovery-tokens <keyid>
This operation generates and returns an additional recovery token β as long as the record isn't currently locked. π€
π Unlock a locked OPAQUE-Store blob
getpwd | sphinx unlock <keyid> <recovery-token>
This operation unlocks a record that has been locked by the servers (like, say, after repeated failed login attempts, or if you forgot your master password π). It requires a valid recovery token. Once unlocked, the record is automatically retrieved β unless the wrong password is provided again. π
β¨ SPHINX CONFIGURATION β¨
okay so the client is configurable through any of these files, and bestie, the order matters, they're read in this order:
/etc/sphinx/config~/.sphinxrc~/.config/sphinx/config./sphinx.cfg
Later files override earlier ones π which is literally the whole point β it lets global settings get overridden by per-user and per-directory settings. slay.
π Client Settings ([client] section)
datadir(default:~/.sphinx) β the directory where client parameters live. Specifically, it holds amasterkeythat's used to derive secrets. If it's missing, theinitcommand generates it. You SHOULD back up and encrypt this master key π no cap.rwd_keys(default:False) β toggles whether the master password is required for authentication of management operations. The oracle is completely oblivious to this setting, it's purely a client-side toggle. In theory you could have different settings for different "records" on the oracle.validate_password(default:True) β stores a 5-bit check digit on the server that helps detect most master password typos, while slightly reducing security.userlist(default:True) β when disabled, it stops the server from correlating all usernames belonging to the same SPHINX user for the same host. If you disable it, the user has to remember which username is used for each host π.address/portβ these two are only used for backward compatibility with old v1 servers. If no record is found with a v2 get operation, SPHINX will then attempt a v1-style get request and see if the record is available from "old times". If a v1 record is found, a new v2-style record is created. After that, a v1 get request for this particular record is not needed anymore.delete_upgraded(default:False) β enables automatic deletion of v1 records after upgrading to v2. This setting is recommended unless you're using v1-only clients like androsphinx. It lets server operators see if their users are finally completely v2, so that they can disable v1 support π₯.thresholdβ the number of servers required for SPHINX operations. If the[servers]section contains more than two entries, this value must be greater than 1 and less than the number of servers listed in the[servers]section:1 < threshold < len(servers).
πΈ Server Settings ([servers] section)
The [servers] section contains one subsection per server. For example:
[servers]
[servers.zero]
host="localhost"
port=10000
ltsigkey = "32byteBase64EncodedValue=="
- Section format:
[servers.<name>]. The name can be freely chosen and can be a public value. It is important to never change it, as long as you want to access your passwords on this server. This name value is used together with other values to create unique record IDs. If you change the name, the record IDs change, and you will not be able to access your old records π so like, don't do that. hostandportβ should match what you set (or its admin publishes) in theoracle(1)server.ltsigkeyβ this is the server's long-term signing key for threshold operations. It should be a base64-encoded value; however, you can also store the raw binary key in a file and use theltsigkey_pathoption instead. This key is only needed for threshold setup, and is not required in single-server mode.
See oracle(1) for more configuration parameters.
π SECURITY CONSIDERATIONS π
- You SHOULD back up and encrypt your
masterkey. You can do this using theqr keyoperation, recording other important details as well. Backing upwebauthn_data_dirfrom the[websphinx]section is also recommended if you're using the web extension and WebAuthn π. rwd_keyssetting:- If
False: protects against offline master password brute-force attacks (a security guarantee of SPHINX). - If
True: prevents denial-of-service attacks where an attacker could change/delete records for known (host, username) pairs if they have the masterkey, but removes the offline brute-force protection.
- If
This is a trade-off between account password availability and master password confidentiality π«Ά.
validate_password: stores a 5-bit check digit on the server that helps to detect most master password typos. If enabled, this setting decreases security slightly but is generally safe to enable.userlist(default: enabled): this configuration setting allows a server operator to correlate records belonging to the same SPHINX user for the same online service. If multiple accounts on the same service are managed by the same SPHINX server, the server operator can detect when auserlistrecord is updated and which SPHINX record belongs to this operation. This leaks some information that can be used by an adversarial server operator to correlate records π.
π Password Entry Example
In this documentation, echo is used only for demonstration. For real usage, use getpwd(1) from the contrib directory if you are not interested in customizing, or consider something like:
echo GETPIN | pinentry | grep '^D' | cut -c3- | sphinx create username example.com ulsd 0
Using pinentry, you can enable double password input, and password quality checks. It's quite versatile β¨.
π REPORTING BUGS π
https://github.com/stef/pwdsphinx/issues/
π AUTHOR π
Written by Stefan Marsiske.
π COPYRIGHT π
Copyright Β© 2024 Stefan Marsiske. License GPLv3+: GNU GPL version 3 or later https://gnu.org/licenses/gpl.html. This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.
π SEE ALSO π
https://www.ctrlc.hu/~stef/blog/posts/sphinx.html
https://www.ctrlc.hu/~stef/blog/posts/oprf.html
https://github.com/stef/opaque-store/
oracle(1), getpwd(1), opaquestore(1)
and that's the whole page bestie, we ate π
β¨ this is sphinx(1) from the pwdsphinx project π go protect those passwords, ily, mwah ππ¦π
π¦ where this page comes from
- nixos 26.05: pwdsphinx 2.0.4
- nixpkgs unstable: pwdsphinx 2.0.4
- ubuntu stonking: pwdsphinx 2.0.4-1 Β· GPL-3.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms