1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698
|
% sphinx(1) | command-line client for the SPHINX password manager
# NAME
sphinx - command-line client for the SPHINX password manager
# 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\nnewpassword" | `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>]
In general if any operation requires a master(input) password, it is
expected on standard input, and any resulting account (output)
password is printed to standard output. In the examples we use `echo`
but it is recommended to use `getpwd(1)` or similar tools to query and pass the
input password.
# DESCRIPTION
SPHINX -- password Store that Perfectly Hides from Itself (No Xaggeration) --
is an information-theoretically secure cryptographic password storage
protocol with strong security guarantees, as 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).
`sphinx` is the command-line client for the SPHINX protocol, it
provides access to all operations over the life-cycle of a password:
init, create, get, change, undo, commit, delete. Additionally it
provides also operations that make this more user-friendly: listing of
users associated with a host and export of the configuration using a
qr code.
`sphinx` not only handles passwords, it is also able to handle (T)OTP
2FA and age keys. Additionally - if installed - `sphinx` also provides
access to `opaquestore(1)`, a simple tool that allows one to store secrets
that need encrypted storage (like keys, phrases, or other data).
## INITIALIZING A CLIENT
```
sphinx init
```
This creates a new master key 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 master key.
If you want to use sphinx on a different device you want to copy this
master key also there. For copying this (and other settings) to the
android client `androsphinx` we have the `qr` operation, see below.
This operation also creates a fixed healthcheck record on the server(s).
## CREATE PASSWORD
Creating a new password for a site is easy, pass your "master"
password on standard input to the client, and provide parameters like
in this example:
```
echo -n 'my input password' | sphinx create username example.com ulsd 0 ' !"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'
```
The parameters to the client are
- Your input password on standard input. Since the input password is
not used to input anything, you can actually use different input
passwords for different user/site combinations. (Unlike with
traditional password managers which have one master password that
encrypts the whole database)
- `create` for the operation, then
- `username` for the username on
- the site `example.com` then
- the password constraints, see sections `PASSWORD RULES` and
`PREDETERMINED PASSWORDS` for more info
If the command runs successfully - the resulting new high-entropy
output password according to the given rules is printed to the
console.
## GET PASSWORD
Getting a password from the sphinx oracle works by running the
following command:
```
echo -n 'my master password' | sphinx get username example.com
```
You supply your master password on standard input, provide the `get`
operation as the first parameter, your `username` as the 2nd and the
`site` as the 3rd parameter. The resulting password is returned on
standard output.
## CHANGE PASSWORD
You might want to (or are forced to regularly) change your password,
this is easy while you can keep your master password unchanged (or
you can change it too, if you want). The command is this:
```
echo -en 'my master password\nnew masterpassword' | sphinx change username example.com 'ulsd' 0 ' !"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'
```
You supply your current master password on standard input, and
separated by a new-line you also provide the new master password. The
new master password can be the same as the old, but can also be a new
password if you want to change also the master password.
You provide the `change` operation as the first parameter to the
client, your `username` as the 2nd and the `site` as the 3rd
parameter. You also can provide similar password generation rule
parameters that were also used to create the original password, in
case your account has new password rules and you want/have to
accommodate them. For more information see the `PASSWORD RULES` and
`PREDETERMINED PASSWORDS` sections below.
Your new new password is returned on standard output. __IMPORTANT__ this
only creates a new output password, but does not activate it. Running a `get`
operation will still respond with the previous password, to activate the new
password, you need to run a `commit` operation, see the next section:
## COMMITTING A CHANGED PASSWORD
After changing the password, you will still get the old password when
running the `get` operation. To switch to use the new password you
have to commit the changes with
```
echo -n 'my master password' | sphinx commit username example.com
```
Depending on your `rwd_keys` configuration setting, you might have to
provide your input password on standard input to this operation.
If all goes well, there is no output expected. If anything goes wrong,
there is going to be an error message and a non-zero exit-code.
## UNDOING A PASSWORD COMMIT
If you somehow messed up and have to go back to use the old password, you can
undo committing your password using:
```
echo -n 'my master password' | sphinx undo username example.com
```
Depending on your `rwd_keys` configuration setting, you might have to
provide your master password on standard input to this operation.
If all goes well, there is no output expected, otherwise there will be
an error message and non-zero exit-code.
## DELETING PASSWORDS
In case you want to delete a password, you can do using the following
command:
```
echo -n "my master password" | sphinx delete username example.com
```
You provide the `delete` operation as the first parameter to the
client, your `username` as the 2nd and the `site` as the 3rd
parameter. This command does not provide any output on the console in
case everything goes well, otherwise an error message and an non-zero
exit code will signal a problem.
Depending on your `rwd_keys` configuration setting, you might have to
provide your master password on standard input to this operation.
## QR CODE CONFIG
In case you want to use phone with the same sphinx server, you need to
export your config to the phone via a QR code.
```
sphinx qr
```
Will display a QR code containing only public information - like the
server host and port, and whether you use rwd_keys. This is mostly
useful if you want to share your setup with a friend or family.
If you want to connect your own phone to the setup used with
pwdsphinx, you also need to export your client secret in the QR code:
```
sphinx qr key
```
This contains your client secret, and you should keep this QR code
confidential. Make sure there is no cameras making copies of this while this QR
code is displayed on your screen.
If for whatever reason you want to display the QR code as an SVG, just append
the `svg` keyword to the end of the `sphinx qr` command.
## HEALTHCHECK
If you have run the `sphinx init` command, then this also has created a fixed
healthcheck record. You can simply check if your setup is ok, by running a
`sphinx healthcheck` operation. You can also try doing the same by running a
`get` operation like this:
```
echo -n 'all ok?' | env/bin/sphinx get healthcheck "sphinx servers"
```
It should output "everything works fine". The difference is, that the health
check only fetches the ratelimiting challenges from all servers and then
aborts. While the get request will affect your ratelimiting difficulty if done
to frequently.
## PASSWORD RULES
When creating or changing passwords you can specify rules limiting the
size and characters allowed in the output password. This is specified
as follows:
The letters `ulsd` stand in order for the following
character classes:
- `u` upper-case letters,
- `l` lower-case letters,
- `s` symbols and
- `d` for digits.
The `s` is a short-cut to allow all of the symbols, if you
are limited by the server which symbols to use, you can specify the
allowed symbols explicitly. Currently these are the symbols supported
(note the leading space char):
```
!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
```
Be careful, if you specify these on the command-line you'll have to
escape the quotes you use for enclosing this list and possibly the
backslash char that is also part of this list. In the `create
username` example above the symbols are correctly escaped, in case you
need to copy/paste them.
For examples how to use these see the section "CREATE PASSWORD" or
"CHANGE PASSWORD".
### DEFAULT RULES
If you do not provide password rules, they will be defaulting to
'ulsd' and length as long as possible, which means 77 characters long
passwords using all four character classes, providing 507 bits of
entropy, way too much.
### RECOMMENDED OUTPUT PASSWORD LENGTH
It is recommended to set the output password size to maximum 12 chars
in case of `ulsd` classes enabled. If you ever have to type in this
output password on a TV remote, or in other stressful situations this
will be a big relief. 12 character long passwords with full entropy
and consisting of all possible printable ASCII chars are
computationally impossible to bruteforce on current password cracking
hardware, as they provide almost 80 bits of entropy, and 15 characters
almost 99 bits of entropy.
## PREDETERMINED OUTPUT PASSWORDS
In case for some reason you cannot use random passwords with your
account, or you want to store a "password" that you cannot change,
like a PIN code for example, or a passphrase shared with your
colleagues, you can specify a maximum 77 character long password, that
will be generated by the SPHINX client for you. In that case the
command line looks like this (note the same syntax also works for the
`change` operation)
```
echo -n 'my master password' | sphinx create username example.com "correct_battery-horse#staple"
```
In this case you cannot specify neither the accepted character
classes, nor the size, nor symbols, these will be deducted from the
predetermined password itself.
## Backward compatibility with v1 SPHINX servers/records
If you still have SPHINX records on the server that were generated using v1,
- and you want to use them -, you have to specify this server also in
the client section like you had to in v1. If there is no record found
with v2 get operations sphinx will attempt a get request for a v1
style record. If a v1 style record is found, a new v2 style record is
created automatically, so no need to check for v1 style records in
this particular case anymore.
Unless you use also other clients that are v1 onl (like androsphinx)
v1 records that are upgraded to v2 can be automatically deleted after
a successful upgrade, for this set `delete_upgraded` to true in the
`[client]` section of your sphinx configuration. This helps server
administrators by keeping their "DB" clean, and having a means to see
how many v1 records are still not upgraded.
## OUTPUT PLUGINS (TOTP & AGE)
It is possible to "store" TOTP secrets and age secret keys using
`sphinx`. To store such a secret and have it automatically handled
correctly (e.g. TOTP verification code output instead of the secret)
just prefix your username with `otp://` for TOTP support and with
`age://` for age key support. The latter, when queried will output a
correctly formatted age private key.
Currently the following converters are supported:
### TOTP
Import a TOTP secret
```sh
% 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:
```sh
% getpwd \
| sphinx create minisig://user example.com >/tmp/minisig.pub
```
`Create` and `Change` SPHINX operations automatically return a public key.
Sign a file `filetosign`:
```sh
% 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:
```sh
% 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 AKE key from SPHINX:
```sh
% getpwd \
| sphinx get age://user localhost \
| pipe2tmpfile age --decrypt -i @@keyfile@@ encryptedfile
```
The `Get` SPHINX operation returns a private key.
### SSH-ED25519
Create key and save public key:
```sh
% getpwd \
| sphinx create ssh-ed25519://test asdf >pubkey
```
`Create` and `Change` SPHINX operations automatically return a public key.
Sign a file:
```sh
% 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 file with public key:
```sh
% 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 (see https://github.com/stef/opaque-store/)
installed and configured (see `opaque-stored.cfg(5)`) correctly you
get a number of additional operations, which allow you to store
traditionally encrypted blobs of information. The following
operations will be available if opaque-store is setup correctly:
```sh
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 operations we first execute a SPHINX get
operation, that calculates the password which is used with
OPAQUE. This means that the input passwords for OPAQUE will be the
strongest possible and essentially un-bruteforcable on their own
(without SPHINX). Of course online bruteforce attacks are still
possible going through SPHINX. But OPAQUE is able to detect wrong
passwords and thus can lock your record after a pre-configured amount
of failed attempts. Of course this does not apply to the operator of
an OPAQUE server, who can circumvent the locking of records. And thus:
### A WARNING: don't let one entity control enough of your SPHINX and OPAQUE-Store servers
As you can see every opaque-store op needs a password on standard
input. This password is run through SPHINX, and the output password is
used in the OPAQUE protocol as the input password. This also means,
that if you use a single server setup for both SPHINX and
OPAQUE-Store, the two servers should not be controlled by the same 3rd
party entity, otherwise this entity is able to offline-bruteforce your
SPHINX master password. If you use either of these services in a
threshold setup, and these threshold servers are controlled by
different entities, you should be ok, as long as no one controls a
threshold number of oracles/servers.
### OPAQUE-Store CLI Parameters
#### KeyId
Every operation provided by the OPAQUE-Storage (O-S) integration needs
a "keyid" parameter, this references your record stored by
O-S. Internally the client uses the configuration value `id_salt`,
together with the name of the O-S server to hash the keyid parameter
into a record id for the O-S Server. This means, that if you lose or
change your `id_salt` parameter or the name of the O-S server, all
your record ids will be different and inaccessible. So it is a good
idea to make a backup of your configuration file containing
these. Note this `id_salt` doesn't really have to be secret, although
it does provide another layer of security-by-obscurity if you do
so.
#### Forced operations
In the case that you are using a threshold setup, some operations
(`replace`, `edit`, `changepwd` and `erase`) require that all servers
successfully participate in the operation. This is to avoid, that the
records on temporarily unavailable servers remain unchanged and lead
later possibly to corruption. If you are sure however that this is ok,
you can provide a `force` parameter on the CLI which reduces the
number of servers successfully participating to the value of your
`threshold` configuration setting.
### Store an encrypted blob
```sh
getpwd | sphinx store <keyid> file-to-store
```
This simply does what it promises, stores the `file-to-store`
encrypted on the OPAQUE-Store server, using a password derived from
SPHINX. Note that this command outputs also a recovery-token, which
you should keep safe in case your record gets locked.
### Retrieving an encrypted opaquestore blob
```sh
getpwd | sphinx read <keyid>
```
Straightforward, no surprise. This gets your previously stored record
and displays it on standard output.
### Overwrite an encrypted opaquestore blob
```sh
getpwd | sphinx replace [force] <keyid> file-to-store
```
Whatever has been stored at `keyid` is now overwritten by an encrypted
`file-to-store`. This only works, if there is already something stored
at `keyid`. All servers must cooperate in this, if one or more are
unavailable this will fail, unless `force` is specified and the
threshold is matched, in which case the servers unavailable will be
corrupted from this point on.
### Edit a opaquestore blob
```sh
getpwd | sphinx edit [force] <keyid>
```
This operation fetches the file stored at `keyid` loads it into your
editor (specified by the `EDITOR` environment variable) and stores the
changes and saved file back on the same `keyid` overwriting the
original.
### Change your password on an opaquestore blob
```sh
getpwd | sphinx changepwd [force] <keyid>
```
This operation does a full change of passwords and keys. Even if you
don't change your own password that you provide to getpwd, SPHINX will
change it's own key, and thus change the output password which will be
used for the password in OPAQUE-store finally resulting in a whole new
and fresh encryption key for your file which gets re-encrypted with
that.
### Delete a stored opaquestore blob
```sh
getpwd | sphinx erase [force] <keyid>
```
Nothing surprising here, does what it promises, deletes the stored
blob referenced by the keyid.
### Get a recovery token
```sh
getpwd | sphinx recovery-tokens <keyid>
```
If your record is not locked, this operation gets you an additional
recovery token.
### Unlock a locked opaquestore blob
```sh
getpwd | sphinx unlock <keyid> <recovery-token>
```
If for some reason (someone online-bruteforcing your record, or you
forgetting your master password) your record becomes locked by the
servers, you can unlock it using a recovery token. This will also
automatically retrieve the record - unless you supply the wrong
password again.
# SPHINX CONFIGURATION
The client can be configured by any of the following files:
- `/etc/sphinx/config`
- `~/.sphinxrc`
- `~/.config/sphinx/config`
- `./sphinx.cfg`
Files are parsed in this order, this means global settings can be
overridden by per-user and per-directory settings.
The client can be configured changing the settings in the `[client]`
and the `[servers]` sections of the config file.
The `datadir` (default: `~/.sphinx`) variable holds the location for
your client parameters. Particularly it contains a masterkey which is
used to derive secrets. The master key - if not available - is
generated by issuing an `init` command. You **SHOULD** back up and
encrypt this master key.
`rwd_keys` toggles if the master password is required for
authentication of management operations.
The oracle is oblivious to this setting, this is purely a client-side
toggle, in theory it is possible to have different settings for
different "records" on the oracle.
`validate_password` Stores a check digit of 5 bits in on the oracle,
this helps to notice most typos of the master password, while
decreasing security slightly.
The `userlist` option (default: True) can disable the usage of userlists. This
prohibits the server to correlate all the records that belong to the same
sphinx user relating to the same host. The cost of this, is that the user has
to remember themselves which usernames they have at which host.
Specify `address` and `port` for backward compatibility with an old v1
server. If there is no record found with v2 get operations sphinx will
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,
so no need to send a v1 get request for this particular record anymore.
`delete_upgraded` enables automatic deletion of v1 records after automatically
upgrading them to v2 records. Unless you use also other clients that are v1
only (like androsphinx) this is the recommended setting, it removes crust and
enables server operators to see if their users are finally completely v2, and
can disable v1 support.
The `threshold` option must specify the number of servers necessary to operate
sphinx. 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).
The `[servers]' section contains subsections for each server like this:
```
[servers]
[servers.zero]
host="localhost"
port=10000
ltsigkey = "32byteBase64EncodedValue=="
```
The subsections all have the the format [server.`name`]. This `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.
The `host` and `port` should match what you set (or its admin publishes) in the
`oracle(1)` server. The `ltsigkey` is the servers long-term signing key for
threshold operations this should be a base64 encoded value. Alternatively you
can also store the raw binary key in a file, which you then specify using the
`ltsigkey_path` value instead. This key only needed for threshold operation, if
you use SPHINX in a single-server setting you don't need this.
# SECURITY CONSIDERATIONS
You **SHOULD** back up and encrypt your master key. Hint you could do
this using the `qr key` operation, recording all the other important
details as well. Backing up your `webauthn_data_dir` from the `[websphinx]`
section is also a good idea, in case you use the webextension and webauthn.
The `rwd_keys` configuration setting, if set to False protects against
offline master password bruteforce attacks - which is also a security
guarantee of the original SPHINX protocol.
The drawback is that for known (host,username) pairs the according
record can be changed/deleted by an attacker if the clients masterkey
is available to them. However neither the master nor the account
password can leak this way. This is merely a denial-of-service attack
vector. If `rwd_keys` is set to True, then this eliminates the
denial-of-service vector, but also negates the offline-bruteforce
guarantee of the SPHINX protocol. This setting is really a compromise
between availability of account passwords versus the confidentiality
of your master password.
The `validate_password` configuration setting if enabled, decreases
security slightly (by 5 bits). In general it should be safe to enable.
The `userlist` configuration setting is by default enabled, and allows a server
operator to correlate records that belong to the same SPHINX user on the same
online service. If you have multiple accounts on an online service and all of
them are handled by the same SPHINX server, the server operator can take note
when a userlist record 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.
In this man page we are using echo only for demonstration, you should
use something like this instead (or even directly `getpwd(1)` from the
contrib directory if you are not interested in customizing):
```
echo GETPIN | pinentry | grep '^D' | cut -c3- | sphinx create username example.com ulsd 0
```
Using pinentry you can go fancy and do double password input, and even have
something checking password quality for you, check it out, 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)`
|