keyfork: add more documentation, unlink root README from crate

This commit is contained in:
Ryan Heywood 2024-02-10 01:30:50 -05:00
parent 1879a250c8
commit 2b8c90fcd5
Signed by: ryan
GPG Key ID: 8E401478A3FBEF72
4 changed files with 90 additions and 2 deletions

55
crates/keyfork/README.md Normal file
View File

@ -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 <jdoe@example.com>" | 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/

View File

@ -19,6 +19,9 @@ type Result<T, E = Box<dyn std::error::Error>> = std::result::Result<T, E>;
pub enum DeriveSubcommands { pub enum DeriveSubcommands {
/// Derive an OpenPGP Transferable Secret Key (private key). The key is encoded using OpenPGP /// Derive an OpenPGP Transferable Secret Key (private key). The key is encoded using OpenPGP
/// ASCII Armor, a format usable by most programs 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")] #[command(name = "openpgp")]
OpenPGP { OpenPGP {
/// Default User ID for the certificate, using the OpenPGP User ID format. /// Default User ID for the certificate, using the OpenPGP User ID format.
@ -72,6 +75,10 @@ pub struct Derive {
command: DeriveSubcommands, command: DeriveSubcommands,
/// Account ID. Required for all derivations. /// 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")] #[arg(long, global = true, default_value = "0")]
account_id: u32, account_id: u32,
} }

View File

@ -9,7 +9,7 @@ mod wizard;
/// The Kitchen Sink of Entropy. /// The Kitchen Sink of Entropy.
#[derive(Parser, Clone, Debug)] #[derive(Parser, Clone, Debug)]
#[command(author, version, about, long_about = None)] #[command(author, version, about, long_about)]
pub struct Keyfork { pub struct Keyfork {
// Global options // Global options
#[command(subcommand)] #[command(subcommand)]
@ -20,25 +20,51 @@ pub struct Keyfork {
pub enum KeyforkCommands { pub enum KeyforkCommands {
/// Derive keys of various formats. These commands require that the Keyfork server is running, /// Derive keys of various formats. These commands require that the Keyfork server is running,
/// which can be started by running a `keyfork recover` command. /// 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), Derive(derive::Derive),
/// Mnemonic generation and persistence utilities. /// Mnemonic generation and persistence utilities.
Mnemonic(mnemonic::Mnemonic), Mnemonic(mnemonic::Mnemonic),
/// Splitting and combining secrets, using Shamir's Secret Sharing. /// 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), Shard(shard::Shard),
/// Derive and deploy keys to hardware. /// 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))] #[command(subcommand_negates_reqs(true))]
Provision(provision::Provision), Provision(provision::Provision),
/// Recover a seed using the requested recovery mechanism and start the Keyfork server. /// 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), Recover(recover::Recover),
/// Utilities to automatically manage the setup of Keyfork. /// Utilities to automatically manage the setup of Keyfork.
Wizard(wizard::Wizard), Wizard(wizard::Wizard),
/// Print an autocompletion file to standard output. /// 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")] #[cfg(feature = "completion")]
Completion { Completion {
#[arg(value_enum)] #[arg(value_enum)]

View File

@ -1,4 +1,4 @@
#![doc = include_str!("../../../README.md")] #![doc = include_str!("../README.md")]
#![allow(clippy::module_name_repetitions)] #![allow(clippy::module_name_repetitions)]