From 2b8c90fcd5f665e7b93c0be3d1e677886d5e0c4b Mon Sep 17 00:00:00 2001 From: ryan Date: Sat, 10 Feb 2024 01:30:50 -0500 Subject: [PATCH] keyfork: add more documentation, unlink root README from crate --- crates/keyfork/README.md | 55 ++++++++++++++++++++++++++++++++ crates/keyfork/src/cli/derive.rs | 7 ++++ crates/keyfork/src/cli/mod.rs | 28 +++++++++++++++- crates/keyfork/src/main.rs | 2 +- 4 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 crates/keyfork/README.md diff --git a/crates/keyfork/README.md b/crates/keyfork/README.md new file mode 100644 index 0000000..46130d3 --- /dev/null +++ b/crates/keyfork/README.md @@ -0,0 +1,55 @@ +# Keyfork: The Kitchen Sink of Entropy + +**Note:** Keyfork operations are meant to be run on an airgapped machine and +Keyfork will error if either any network interfaces are detected or if Keyfork +is running on a system with a kernel using an insecure random number generator. + +An all-inclusive crate encapsulating end-user functionality of the Keyfork +ecosystem, the Keyfork binary includes all mechanisms that should be exposed to +the user when running Keyfork. Information about what operations Keyfork +performs are available in detail by running `keyfork help` (each subcommand has +thorough documentation) or in the [`docs`] mdBook, but here's a quick overview: + +## Getting Started with Keyfork + +Keyfork offers two options for getting started. For multi-user setups, it is +best to look at the detailed documentation for Keyfork Shard. For single-user +setups, `keyfork mnemonic generate` will (by default) create a 256-bit mnemonic +phrase that can be used to start Keyfork. *Store this phrase*, as it's the only +way you'll be able to start Keyfork in the future. It is recommended to use a +mnemonic recovery sheet or a printed-steel solution such as the [Billfodl] or +[Cryptosteel Capsule]. + +```sh +keyfork mnemonic generate +``` + +Once a mnemonic has been generated and stored in a secure manner, Keyfork can +be started by "recovering" the server from the mnemonic backup mechanism: + +```sh +keyfork recover mnemonic +``` + +## Deriving Keys + +Keyfork's primary goal is to derive keys. These keys can later be used for +things such as signing documents and artifacts or decrypting payloads. +Keyfork's first derivation target is OpenPGP, a protocol supporting many +cryptographic operations. OpenPGP keys require a User ID, which can be used to +identify the owner of the key, either by name or by email. To get an OpenPGP +public key (more accurately known as a "cert"), the [`sq`][sq] tool is used to +convert a key to a certificate: + +```sh +keyfork derive openpgp "John Doe " | sq key extract-cert +``` + +All Keyfork derivations are intended to be reproducible. Because of this, +Keyfork derived keys can be recreated at any time, only requiring the knowledge +of how the key was made. + +[`docs`]: /public/keyfork/src/branch/main/docs/src/SUMMARY.md +[Billfodl]: https://privacypros.io/products/the-billfodl/ +[Cryptosteel Capsule]: https://cryptosteel.com/product/cryptosteel-capsule-solo/ +[sq]: https://gitlab.com/sequoia-pgp/sequoia-sq/ diff --git a/crates/keyfork/src/cli/derive.rs b/crates/keyfork/src/cli/derive.rs index 1e247f9..7b2dc2f 100644 --- a/crates/keyfork/src/cli/derive.rs +++ b/crates/keyfork/src/cli/derive.rs @@ -19,6 +19,9 @@ type Result> = std::result::Result; pub enum DeriveSubcommands { /// Derive an OpenPGP Transferable Secret Key (private key). The key is encoded using OpenPGP /// ASCII Armor, a format usable by most programs using OpenPGP. + /// + /// The key is generated with a 24-hour expiration time. The operation to set the expiration + /// time to a higher value is left to the user to ensure the key is usable by the user. #[command(name = "openpgp")] OpenPGP { /// Default User ID for the certificate, using the OpenPGP User ID format. @@ -72,6 +75,10 @@ pub struct Derive { command: DeriveSubcommands, /// Account ID. Required for all derivations. + /// + /// An account ID may not be relevant for the derivation being performed, but the lack of an + /// account ID can often come as a hindrance in the future. As such, it is always required. If + /// the account ID is not relevant, it is assumed to be `0`. #[arg(long, global = true, default_value = "0")] account_id: u32, } diff --git a/crates/keyfork/src/cli/mod.rs b/crates/keyfork/src/cli/mod.rs index 2a76c04..ec3dd31 100644 --- a/crates/keyfork/src/cli/mod.rs +++ b/crates/keyfork/src/cli/mod.rs @@ -9,7 +9,7 @@ mod wizard; /// The Kitchen Sink of Entropy. #[derive(Parser, Clone, Debug)] -#[command(author, version, about, long_about = None)] +#[command(author, version, about, long_about)] pub struct Keyfork { // Global options #[command(subcommand)] @@ -20,25 +20,51 @@ pub struct Keyfork { pub enum KeyforkCommands { /// Derive keys of various formats. These commands require that the Keyfork server is running, /// which can be started by running a `keyfork recover` command. + /// + /// Derived keys are reproducible: assuming the same arguments are used when deriving a key for + /// a second time, the key will be _functionally_ equivalent. This means keys don't need to be + /// persisted to cold storage or left hot in a running program. They can be derived when + /// they're needed and forgotten when they're not. Derive(derive::Derive), /// Mnemonic generation and persistence utilities. Mnemonic(mnemonic::Mnemonic), /// Splitting and combining secrets, using Shamir's Secret Sharing. + /// + /// Keys can be split such that a certain amount of users, from a potentially even-larger + /// amount of users, can be used to recreate a key. This creates resilience for a key, as in a + /// "seven of nine" scenario, nine people in total are capable of recreating a key, but only + /// seven may be required. Shard(shard::Shard), /// Derive and deploy keys to hardware. + /// + /// Keys existing in hardware creates a situation where it is unlikely (but not impossible) for + /// a key to be extracted. While a key in memory could be captured by a rootkit or some other + /// privilege escalation mechanism, a key in hardware would require a hardware exploit to + /// extract the key. + /// + /// It is recommended to provision keys whenever possible, as opposed to deriving them. #[command(subcommand_negates_reqs(true))] Provision(provision::Provision), /// Recover a seed using the requested recovery mechanism and start the Keyfork server. + /// + /// Once the Keyfork server is started, derivation requests can be performed. The Keyfork seed + /// is kept solely in the Keyfork server. Derivations with less than two indices are not + /// permitted, to ensure a seed often used to derive keys for multiple different paths is not + /// leaked by any individual deriver. Recover(recover::Recover), /// Utilities to automatically manage the setup of Keyfork. Wizard(wizard::Wizard), /// Print an autocompletion file to standard output. + /// + /// Keyfork does not manage the installation of completion files. Consult the documentation for + /// the shell for which documentation has been generated on the appropriate location to store + /// completion files. #[cfg(feature = "completion")] Completion { #[arg(value_enum)] diff --git a/crates/keyfork/src/main.rs b/crates/keyfork/src/main.rs index 23b369b..58ec548 100644 --- a/crates/keyfork/src/main.rs +++ b/crates/keyfork/src/main.rs @@ -1,4 +1,4 @@ -#![doc = include_str!("../../../README.md")] +#![doc = include_str!("../README.md")] #![allow(clippy::module_name_repetitions)]