2023-08-16 01:23:15 +00:00
|
|
|
# keyfork #
|
|
|
|
|
|
|
|
An opinionated and modular toolchain for generating and managing a wide range
|
|
|
|
of cryptographic keys offline and on smartcards from a shared bip39 mnemonic
|
|
|
|
phrase.
|
|
|
|
|
2024-01-10 18:21:21 +00:00
|
|
|
Keyfork can be used by organizations and solo users, for the purposes of
|
|
|
|
disaster recovery, cold storage, and reproducibility of private keys and secret
|
|
|
|
data. Keyfork achieves this by using a bip32 seed loaded into an agent to
|
|
|
|
generate deterministic and unique keypairs. This ensures only the agent has
|
|
|
|
control over the mnemonic itself, and other components can request
|
|
|
|
deterministic data. The seed can be split using the Keyfork Shard mechanism,
|
|
|
|
which utilizes Shamir's Secret Sharing to allow "M-of-N" recovery of the seed.
|
2023-08-16 10:43:40 +00:00
|
|
|
|
2024-01-15 05:18:38 +00:00
|
|
|
All crate licenses are notated using the "license" field in their respective
|
|
|
|
Cargo.toml. As a general rule, As a general rule, crates with binaries are
|
|
|
|
licensed AGPL and crates only used as a library are licensed MIT. Forked
|
|
|
|
projects retain their original licenses.
|
|
|
|
|
2023-09-21 22:30:48 +00:00
|
|
|
## Dependency Policy
|
|
|
|
|
|
|
|
Dependencies must not be added to core utilities such as seed generation and
|
|
|
|
path derivation without a _really_ good reason we can't implement it ourselves,
|
|
|
|
such as cryptography libraries. For instance, `keyfork-derive-util` _only_
|
|
|
|
utilizes cryptography libraries, `serde`, and `thiserror`, with the latter two
|
|
|
|
being audited dependencies. Utilities such as forklets (applications that
|
|
|
|
use derived data, such as an OpenPGP keychain generator) and the kitchen-sink
|
|
|
|
`keyfork` utility may pull in additional dependencies _as needed_, but should
|
|
|
|
strive to use the standard library as much as possible. To avoid code reuse,
|
|
|
|
additional crates (such as the `smex` crate) may be used to share functionality
|
|
|
|
across several crates.
|
|
|
|
|
2023-09-21 23:08:07 +00:00
|
|
|
## Keyfork Top-Level Binary
|
|
|
|
|
|
|
|
The `keyfork` binary is the most user-friendly interface for interacting with
|
2024-01-10 18:21:21 +00:00
|
|
|
the Keyfork toolchain. It offers commands that are intended to accept
|
|
|
|
human-readable input and produce human-readable output, and can be described as
|
|
|
|
a "Terminal User Interface" rather than a "Command Line Interface". An example
|
|
|
|
of a `keyfork` command would be `keyfork wizard generate-shard-secret`, which
|
|
|
|
will generate a secret, provision smart cards, and export the newly-generated
|
|
|
|
Shard file. Processes included in the `keyfork` binary should not accept
|
|
|
|
arbitrary strings or numbers, such as manual derivation paths, and instead
|
|
|
|
should ask for values like "account index" and generate their own magic values
|
|
|
|
if necessary.
|
2023-09-21 23:08:07 +00:00
|
|
|
|
2023-09-21 22:30:48 +00:00
|
|
|
---
|
|
|
|
|
2024-01-10 18:21:21 +00:00
|
|
|
Note: The following features are proposed, and may not yet be implemented.
|
2023-08-16 01:23:15 +00:00
|
|
|
|
|
|
|
## Features
|
|
|
|
|
|
|
|
* Modular
|
2024-01-10 18:21:21 +00:00
|
|
|
* Standalone binaries can derive/manage keys/config
|
2023-08-16 01:23:15 +00:00
|
|
|
* Modules handle use cases like ssh, pgp, webauthn, crypto-assets, etc
|
|
|
|
* Module contract is dead simple and can be written in any language
|
|
|
|
* Recoverable
|
2024-01-10 18:21:21 +00:00
|
|
|
* Config file and 24 word mnemonic phrase to recover *every* key
|
|
|
|
* Shard mechanism allows for "M-of-N" recovery of seed if lost
|
2023-08-16 01:23:15 +00:00
|
|
|
* Unpredictable
|
2024-01-10 18:21:21 +00:00
|
|
|
* Generate a BIP39 phrase from OS or physicalized entropy
|
|
|
|
* Provide and use BIP39 passphrase from user supplied entropy
|
2023-08-16 01:23:15 +00:00
|
|
|
* Read up on [https://milksad.info](milksad) to understand why this matters!
|
2024-01-10 18:21:21 +00:00
|
|
|
* Deterministic
|
|
|
|
* Given the same seed, repeated derivation requests will be reproducible
|
|
|
|
* Any secret data can be derived again at any point in the future
|
2023-08-16 01:23:15 +00:00
|
|
|
* Offline
|
|
|
|
* Will exit if network access is detected to force you to keep keys offline
|
|
|
|
* Helps limit the risk of supply chain attacks
|
|
|
|
* Intended for use with QubesOS Vault VM, AirgapOS, etc
|
|
|
|
* Private keys are installed to HSMs/TEEs for use by online machines
|
|
|
|
|
|
|
|
## Install
|
|
|
|
|
|
|
|
These steps will allow you to prove that at least two Distrust engineers
|
|
|
|
signed off on the produced binaries, signaling that they reproduced them from
|
|
|
|
source code and got identical results, in addition to our usual two-party code
|
|
|
|
review processes.
|
|
|
|
|
|
|
|
This minimizes a single point of trust (and failure) in our binary release
|
|
|
|
process.
|
|
|
|
|
|
|
|
See the [Reproducible Builds](https://reproducible-builds.org/) project for
|
|
|
|
more information on these practices.
|
|
|
|
|
|
|
|
We use git for all development, releases, and signing. Unfortunately git has no
|
|
|
|
native method for large file storage or multi-signature workflows so some git
|
|
|
|
add-ons are required.
|
|
|
|
|
|
|
|
To follow these steps please install [git-lfs][gl] and [git-sig][gs].
|
|
|
|
|
|
|
|
[gs]: https://git.distrust.co/public/git-sig
|
|
|
|
[gl]: https://git-lfs.com
|
|
|
|
|
|
|
|
1. Clone repo
|
|
|
|
|
|
|
|
```sh
|
|
|
|
git clone https://git.distrust.co/public/keyfork
|
|
|
|
cd keyfork
|
|
|
|
```
|
|
|
|
|
|
|
|
2. Review binary signatures
|
|
|
|
|
|
|
|
```sh
|
|
|
|
git sig verify
|
|
|
|
```
|
|
|
|
|
|
|
|
Note: See Trust section below for expected keys/signers
|
|
|
|
|
|
|
|
3. Install binary
|
|
|
|
|
|
|
|
```
|
|
|
|
make install
|
|
|
|
```
|
|
|
|
|
2024-01-10 01:39:11 +00:00
|
|
|
## Basic Usage
|
|
|
|
|
|
|
|
### Personal Setup
|
|
|
|
|
|
|
|
On an airgapped system, run the following command to generate a BIP-0039
|
|
|
|
mnemonic encoding a generated seed:
|
|
|
|
|
|
|
|
```sh
|
|
|
|
keyfork mnemonic generate
|
|
|
|
```
|
|
|
|
|
2024-01-10 01:41:57 +00:00
|
|
|
Once generated, the mnemonic should be written down and stored in a secure
|
|
|
|
location such as a safe.
|
|
|
|
|
2024-01-10 01:39:11 +00:00
|
|
|
<!--
|
|
|
|
The default format is to use system entropy, but playing cards, tarot cards, or
|
|
|
|
dice can be used to generate physical entropy
|
|
|
|
-->
|
|
|
|
|
|
|
|
The Keyfork server can be started by running the following command:
|
|
|
|
|
|
|
|
```sh
|
|
|
|
keyfork recover mnemonic
|
|
|
|
```
|
|
|
|
|
|
|
|
### Group Setup
|
|
|
|
|
|
|
|
This guide assumes you are sharding to an `N`-of-`M` system with `I` smart
|
|
|
|
cards per shardholder. The variables will be used in the following commands as
|
|
|
|
`$N`, `$M`, and `$I`. The smart cards will be factory reset during the process.
|
|
|
|
|
|
|
|
On an airgapped system, run the following command to generate a file containing
|
|
|
|
encrypted shards of a generated seed:
|
|
|
|
|
|
|
|
```sh
|
2024-01-15 04:52:20 +00:00
|
|
|
keyfork wizard generate-shard-secret --threshold $N --max $M --keys-per-shard $I --output shards.pgp
|
2024-01-10 01:39:11 +00:00
|
|
|
```
|
|
|
|
|
2024-01-10 01:41:57 +00:00
|
|
|
Once generated, the shards file can be safely stored in any location, as the
|
|
|
|
only information that can be obtained from the shard file is the `$N` value.
|
|
|
|
|
2024-01-10 01:39:11 +00:00
|
|
|
If all shardholders are physically present, the Keyfork server can be started
|
|
|
|
by running the following command:
|
|
|
|
|
|
|
|
```sh
|
|
|
|
keyfork recover shard
|
|
|
|
```
|
|
|
|
|
|
|
|
Otherwise, the Keyfork server can be started by transporting the shards to the
|
|
|
|
machine using the following command:
|
|
|
|
|
|
|
|
```sh
|
|
|
|
keyfork recover remote-shard
|
|
|
|
```
|
|
|
|
|
|
|
|
Each shard can be transported by running the following command:
|
|
|
|
|
|
|
|
```sh
|
|
|
|
keyfork shard transport shard.pgp
|
|
|
|
```
|
|
|
|
|
|
|
|
### Deriving Keys
|
|
|
|
|
|
|
|
Keys can be derived from Keyfork using the `keyfork derive` command, such as
|
|
|
|
the following command for an OpenPGP certificate with one of each subkey:
|
|
|
|
|
|
|
|
```sh
|
|
|
|
keyfork derive openpgp "Ryan Heywood (RyanSquared) <ryan@distrust.co>"
|
|
|
|
```
|
|
|
|
|
2023-08-16 01:23:15 +00:00
|
|
|
## Usage
|
|
|
|
|
2024-01-15 05:13:47 +00:00
|
|
|
Detailed usage instructions can be found in the [`docs`] mdBook,
|
2024-01-10 01:39:11 +00:00
|
|
|
which can be opened in-browser by running
|
2024-01-15 05:13:47 +00:00
|
|
|
`mdbook serve --open docs`.
|
2023-12-27 19:05:34 +00:00
|
|
|
|
2024-01-15 05:13:47 +00:00
|
|
|
[`docs`]: /public/keyfork/src/branch/main/docs/src/SUMMARY.md
|
2024-01-15 04:48:02 +00:00
|
|
|
|
2023-12-27 19:05:34 +00:00
|
|
|
<!--
|
2023-08-16 01:23:15 +00:00
|
|
|
```
|
|
|
|
keyfork generate [-c,--config=<file>]
|
|
|
|
Generate new mnemonic optionally public keys defined by config
|
|
|
|
keyfork recover [-c,--config=<file>] [-a,--agent]
|
|
|
|
Recover keychain and optionally config defined pubkeys from mnemonic
|
|
|
|
Optionally run a daemon to supply keys to subcommands
|
|
|
|
keyfork version
|
|
|
|
Show version information.
|
|
|
|
keyfork help
|
|
|
|
Show this text.
|
|
|
|
keyfork [command]
|
|
|
|
Commands receive bip32 root as stdin
|
|
|
|
Commands return output and config data as json over stdout back to keyfork
|
|
|
|
keyfork [command] help
|
|
|
|
Show help for a particular sub-command
|
|
|
|
```
|
|
|
|
|
|
|
|
## Examples
|
|
|
|
|
|
|
|
#### Generate a new mnemonic to write to paper
|
|
|
|
|
|
|
|
```
|
|
|
|
$ keyfork generate
|
|
|
|
|
|
|
|
> milk sad wage cup reward umbrella raven visa give list decorate bulb gold raise twenty fly manual stand float super gentle climb fold park
|
|
|
|
```
|
|
|
|
|
|
|
|
#### Recover a mnemonic with a passphrase and spawn agent
|
|
|
|
|
|
|
|
```
|
|
|
|
$ keyfork recover --agent
|
|
|
|
|
|
|
|
> mnemonic: ********
|
|
|
|
> passphrase: ********
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
#### Derive deterministic PGP keychain from agent key in default "sq" path
|
|
|
|
|
|
|
|
Requires ```keyfork-pgp``` binary in $PATH
|
|
|
|
|
|
|
|
```
|
|
|
|
$ keyfork pgp --format=sq
|
|
|
|
$ sq decrypt secret.pgp
|
|
|
|
```
|
|
|
|
|
|
|
|
#### Install deterministic PGP subkeys from agent key to a smartcard
|
|
|
|
|
|
|
|
Requires ```keyfork-pgp``` binary in $PATH
|
|
|
|
|
|
|
|
```
|
|
|
|
$ keyfork pgp install --device=nitrokey
|
|
|
|
$ gpg --card-status
|
|
|
|
```
|
|
|
|
|
|
|
|
#### Install first deterministic PIV key from agent key to smartcard on slot 1
|
|
|
|
|
|
|
|
Requires ```keyfork-piv``` binary in $PATH
|
|
|
|
|
|
|
|
```
|
|
|
|
$ keyfork piv install --device=yubikey --key=1 --slot=1
|
|
|
|
|
|
|
|
> Management Key: ****
|
|
|
|
> User Pin: ****
|
|
|
|
> Admin Pin: ****
|
|
|
|
|
|
|
|
$ ssh-keygen -D "$OPENSC_LIBS/opensc-pkcs11.so" -e
|
|
|
|
```
|
|
|
|
|
|
|
|
#### Derive first deterministic BIP44 address for Bitcoin Account 1
|
|
|
|
|
|
|
|
Requires ```keyfork-bip44``` binary in $PATH
|
|
|
|
|
|
|
|
```
|
|
|
|
$ keyfork bip44 --path=bitcoin
|
|
|
|
|
|
|
|
> m/44'/0'/0'/0/0: 12DefCMhYVv4sBQikyXKMciAoX2wgzhWqb
|
|
|
|
```
|
2023-12-27 19:05:34 +00:00
|
|
|
-->
|