opaquestore(1)
β¨ NAME β¨
opaquestore β the command-line client for OPAQUE-Store π
Like, the little terminal bestie that talks to your OPAQUE-Store server. She's simple, she's powerful, she takes your password on stdin and never asks questions π
πΈ SYNOPSIS πΈ
`opaquestore` genltsigkey [private-key path] [public-key path]
echo -en 'password\ntoken2store' | `opaquestore` create <keyid>
echo -n 'password' | `opaquestore` get <keyid>
echo -en 'password\ntoken2update' | `opaquestore` update <keyid>
echo -en 'password\ntoken2update' | `opaquestore` force-update <keyid>
echo -n 'password' | `opaquestore` delete <keyid>
echo -n 'password' | `opaquestore` force-delete <keyid>
echo -n 'password' | `opaquestore` recovery-tokens <keyid>
echo -n <recovery-token> | `opaquestore` unlock <keyid>
π¦ DESCRIPTION π¦
Okay so picture this: OPAQUE-Store is a simple protocol that lets literally anyone store encrypted blobs of information online, and the only thing you need to get that info back is a password. That's it. No cap. And yeah, the name is not a coincidence β it uses the OPAQUE protocol to pull this off. Specifically, OPAQUE-Store uses the export_key feature of OPAQUE to encrypt the data that gets stored on the OPAQUE-Storage server. Iconic behaviour, honestly β¨
If you want the full lore, you might wanna read this blog-post on the topic and for more info:
https://www.ctrlc.hu/~stef/blog/posts/How_to_recover_static_secrets_using_OPAQUE.html
Now here's the part that makes her extra: OPAQUE-Store goes beyond the original OPAQUE protocol as specified by the IRTF/CFRG, and also supports a threshold variant of OPAQUE π₯ In a threshold setup you have a number N of servers that all hold a share of your secret, and at least a threshold number T of these need to cooperate to recover the secret. The way that gives you extra robustness and dillution of responsibility β losing a server is not the end of the world, bestie π β while at the same time increasing security, because an attacker now has to compromise at least T servers to get access to some information. Main character security architecture, fr fr π
π» Command-line usage and examples
It is warmly recommended to use pwdsphinx (https://github.com/stef/pwdsphinx) as a front-end to opaquestore, because it handles passwords in a most secure manner. But if you wanna use a different password manager, no worries β the CLI interface documented below is right there for you π«Ά
π Passwords and Records
opaquestore takes the password always on the standard input. And if you're creating or updating a record, the record itself is also expected on the standard input. The password and the record β if required β are separated by a newline character π
π·οΈ KeyIds
KeyIds are the identifiers you use to address your records, and they can be literally any kind of string. Internally this keyId is hashed using the id_salt from the configuration's [client] section into a unique identifier.
It is very warmly recommended to set this to some random value, and to back this value up. This salt is necessary to access your records β no salt, no access, periodt π And if you use a commonly used salt (i.e. the default salt), chances are high that there are collisions for record ids, and that people can guess your record ids. So like... don't do that π
π Store a new record
Storing a record needs 3 parameters:
- the password, on standard input, terminated by a newline.
- the record itself until the end of the standard input.
- and a keyId with which you can reference and act on this record.
$ echo -en 'password\ntoken2store' | opaquestore create <keyId>
Here is a contrived example:
echo -en "mypassword\!sMyV0ice\nmy secretty token data that i need to protect and store using opaque" | opaquestore create myfirstblob
In this example:
- the password is
"mypassword!sMyV0ice" - the record is:
"my secretty token data that i need to protect and store using opaque" - and the keyId is
"myfirstblob"
π Get a record
Retrieving a record has to parameters:
- the password on standard input
- the keyId as the 2nd parameter to
opaquestore
$ echo -n 'password' | opaquestore get <keyId>
An example fetching the record created in the previous example:
echo -en "mypassword\!sMyV0ice" | opaquestore get myfirstblob
π Update a record
It is possible to update a record in place, and it's essentially the same as the creation of a record. But here's the thing you gotta know: this operation only succeeds if all servers need to process this request β not only those needed for matching the threshold. You want to update the record on all servers, not just some. Like, everyone gets the update, no stragglers π
$ echo -en 'password\ntoken2update' | opaquestore update <keyId>
But okay, if you do not care if some servers will not be updated, and you really know what you are doing, you can use the alternative command force-update. In this case the operation will succeed if at least the threshold is matched.
β οΈ Note however: if any of the servers that did not participate in the forced update will participate in later operations, they will corrupt later operations, so you might want to remove those servers from your config. Not me warning you twice, but like, I'm warning you twice π
$ echo -en 'password\ntoken2update' | opaquestore force-update <keyId>
π Delete a record
Deleting a record is very straight forward: you need your password and keyId, and you need to ensure that all servers that store this record will all be available. The operation will fail if some servers are not available.
$ echo -n 'password' | opaquestore delete <keyId>
Similarly to the update operation, there's also a forced delete operation, which will succeed if at least the threshold is matched. Servers not available during this forced delete will still hold the record β so if your setup has a n-out-of-2*n setup, that could mean you still have enough shares even after a forced-delete π
$ echo -n 'password' | opaquestore force-delete <keyId>
π§ Get some recovery-tokens
So an attacker might be trying different passwords for your record, and after a certain amount of consecutive password failures (by default 3) the server locks down the record π A locked record can only be unlocked with a recovery-token. And heads up: it is not possible to ask for recovery-tokens when a record is already locked.
$ echo -n 'password' | opaquestore recovery-tokens <keyId>
π Unlock a locked record using a recovery token
If a record is locked, and you have a valid recovery-token, you can reset the failure counter:
$ echo -n <recovery-token> | opaquestore unlock <keyId>
π Generate long-term signature keys
If you run a server, you need to generate some long-term signing keys if you want to use this server in a threshold setup. And if you don't provide the path to the keys, the secret-key will be taken from the ltsigkey config value in your opaque-storaged configuration, and the public-key will be the same as the secret-key, but with a .pub extension β¨
$ opaquestore genltsigkey [secret-key path] [public-key path]
π‘οΈ SECURITY CONSIDERATIONS π‘οΈ
You should back up and encrypt your master key. That's the whole vibe. Do it. Bestie, please π«Ά
π REPORTING BUGS π
https://github.com/stef/opaque-store/issues/
Found a bug? Tell the devs, not the group chat π
π AUTHOR π
Written by Stefan Marsiske.
π COPYRIGHT π
Copyright Β© 2024 Stefan Marsiske. License GPLv3+: GNU GPL version 3 or later https://gnu.org/licenses/gpl.html (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/How_to_recover_static_secrets_using_OPAQUE.html
opaque-store.cfg(5)
and that's the whole page, bestie β¨ you just read opaquestore(1) from the OPAQUE-Store command-line client manual β go forth and store your secrets, and don't forget that master key backup πππ¦
π¦ where this page comes from
- debian trixie: opaque-store 0.2.0-3 Β· GPL-3.0-or-later
- ubuntu questing: opaque-store 0.2.0-3
- ubuntu resolute: opaque-store 0.2.0-3build1 Β· GPL-3.0-or-later
- ubuntu stonking: opaque-store 0.2.0-3build1 Β· 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