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.
Go to file
Ryan Heywood 6a3244df01
Cargo.lock: bump g2p, remove syn 1.x
2024-08-14 14:31:03 -04:00
.cargo .cargo/config.toml: add registry configuration :) 2024-03-24 22:52:27 -04:00
crates keyfork-qrcode: use image::ImageReader over image::io::Reader (deprecated) 2024-08-14 13:50:48 -04:00
docs keyfork-mnemonic-util => keyfork-mnemonic 2024-08-01 09:50:30 -04:00
scripts release keyfork v0.2.4 2024-08-11 17:33:41 -04:00
.gitignore keyfork-user-guide: more additions 2023-10-19 08:53:59 -05:00
CHANGELOG.md release keyfork v0.2.4 2024-08-11 17:33:41 -04:00
Cargo.lock Cargo.lock: bump g2p, remove syn 1.x 2024-08-14 14:31:03 -04:00
Cargo.toml Cargo.lock: bump multiple deps to deduplicate 2024-08-12 00:31:18 -04:00
LICENSE-AGPL-3.0.txt add licenses 2023-11-16 21:56:57 -05:00
LICENSE-MIT.txt add licenses 2023-11-16 21:56:57 -05:00
Makefile keyfork-mnemonic-util: bump version before publish 2024-02-22 21:46:34 -05:00
README.md fix: specify OpenPGP 2024-04-29 17:57:05 -04:00
bacon.toml fry up some bacon 2024-08-11 23:19:39 -04:00
deny.toml deny.toml: update to not use deprecated keys 2024-08-11 23:48:44 -04:00

README.md

keyfork

An opinionated and modular toolchain for generating and managing a wide range of cryptographic keys offline and on smartcards from a shared BIP-0039 mnemonic phrase. BIP-0039 phrases are used to calculate a BIP-0032 seed, which is used for hierarchical deterministic key derivation.

Note: The difference between the data encoded in a BIP-0039 mnemonic, and the BIP-0032 seed, is that a BIP-0039 mnemonic of any length can be used to generate a BIP-0032 seed of a static length (512 bits). Keyfork makes use of a BIP-0039 mnemonic and does not accept just a BIP-0032 seed - it will be treated as the entropy provided for a mnemonic, or rejected outright for being of an invalid size.

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 loading a BIP-0032 seed into an agent to generate deterministic and unique keypairs. This ensures only the agent has control over the root seed itself, and other components can request deterministic data. The BIP-0039 data can also be split using the Keyfork Shard mechanism, which utilizes Shamir's Secret Sharing to allow "M-of-N" recovery of the data.

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.

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.

Keyfork Top-Level Binary

The keyfork binary is the most user-friendly interface for interacting with 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.


Note: The following features are proposed, and may not yet be implemented.

Features

  • Modular
    • Standalone binaries can derive/manage keys/config
    • Modules handle use cases like ssh, pgp, webauthn, crypto-assets, etc
    • Module contract is dead simple and can be written in any language
  • Recoverable
    • Config file and 24 word mnemonic phrase to recover every key
    • Shard mechanism allows for "M-of-N" recovery of seed if lost
  • Unpredictable
    • Generate a BIP-0039 phrase from OS or physicalized entropy
    • Provide and use BIP-0039 passphrase from user supplied entropy
    • Read up on milksad to understand why this matters!
  • Deterministic
    • Given the same seed, repeated derivation requests will be reproducible
    • Any secret data can be derived again at any point in the future
  • 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

  1. Clone repo

    git clone https://git.distrust.co/public/stack
    
  2. Verify Git signatures

    git verify-commit HEAD
    
  3. Install binary

    cargo install --path crates/keyfork
    
  4. Optionally, build binary for distribution

    cargo build --release --bin keyfork
    

    The binary will be made available in target/release/.

Basic Usage

Personal Setup

On an airgapped system, run the following command to generate a BIP-0039 mnemonic encoding a generated seed:

keyfork mnemonic generate

Once generated, the mnemonic should be written down and stored in a secure location such as a safe.

The Keyfork server can be started by running the following command:

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 card OpenPGP slots 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:

keyfork wizard generate-shard-secret --threshold $N --max $M --keys-per-shard $I --output shards.pgp

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.

If all shardholders are physically present, the Keyfork server can be started by running the following command:

keyfork recover shard

Otherwise, the Keyfork server can be started by transporting the shards to the machine using the following command:

keyfork recover remote-shard

Each shard can be transported by running the following command:

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:

keyfork derive openpgp "Ryan Heywood (RyanSquared) <ryan@distrust.co>"

Usage

Detailed usage instructions can be found in the docs mdBook, which can be opened in-browser by running mdbook serve --open docs.