algae_cli/lib.rs
1//! The Algae simplified encryption command set: support routines and implementation library.
2//!
3//! # The CLI
4//!
5//! You can install the CLI tool with:
6//!
7//! ```console
8//! $ cargo install algae-cli
9//! ```
10//!
11//! Algae is a simplified profile of the excellent [age](https://age-encryption.org/v1) format.
12//!
13//! It implements five functions for the most common operations, and tries to be as obvious and
14//! hard-to-misuse as possible, without being prohibitively hard to use, and while retaining
15//! forward-compatibility with age (all algae products can be used with age, but not all age
16//! products may be used with algae).
17//!
18//! To start with, generate a keypair with `algae keygen`. This will generate two files:
19//! `identity.txt.age`, a passphrase-protected keypair, and `identity.pub`, the public key in plain.
20//!
21//! To encrypt a file, use `algae encrypt -k identity.pub filename`. As this uses the public key, it
22//! doesn't require a passphrase. The encrypted file is written to `filename.age`. To decrypt it,
23//! use `algae decrypt -k identity.txt.age filename.age`. As this uses the secret key, it will
24//! prompt for its passphrase. The decoded file is written back to `filename` (i.e. without the
25//! `.age` suffix).
26//!
27//! To obtain a plaintext `identity.txt` (i.e. to remove the passphrase), use
28//! `algae reveal identity.txt.age`. To add a new passphrase on a plaintext identity, use
29//! `algae protect identity.txt`. These commands are not special to identity files: you can
30//! `protect` (encrypt) and `reveal` (decrypt) arbitrary files with a passphrase.
31//!
32//! # The profile
33//!
34//! - Keypair-based commands use [X25519](age::x25519).
35//! - Passphrase-based commands use [scrypt](age::scrypt).
36//! - Plugins are not supported.
37//! - Multiple recipients are not supported (age-produced multi-recipient files _may_ be decrypted).
38//! - Identity files with multiple identities are not supported (they _might_ work, but behaviour is unspecified).
39//! - Passphrase entry is done with `pinentry` when available, and falls back to a terminal prompt.
40//!
41//! # The library
42//!
43//! This crate is a little atypical in that it deliberately exposes the CLI support structures as
44//! its library, for the purpose of embedding part or parcel of the Algae command set or conventions
45//! into other tools.
46//!
47//! For example, you can insert Algae's `encrypt` and `decrypt` in a [tokio] + [clap] program:
48//!
49//! ```no_run
50//! use clap::Parser;
51//! use miette::Result;
52//! use algae_cli::cli::*;
53//!
54//! /// Your CLI tool
55//! #[derive(Parser)]
56//! enum Command {
57//! Encrypt(encrypt::EncryptArgs),
58//! Decrypt(decrypt::DecryptArgs),
59//! }
60//!
61//! #[tokio::main]
62//! async fn main() -> Result<()> {
63//! let command = Command::parse();
64//! match command {
65//! Command::Encrypt(args) => encrypt::run(args).await,
66//! Command::Decrypt(args) => decrypt::run(args).await,
67//! }
68//! }
69//! ```
70//!
71//! Or you can prompt for a passphrase with the same flags and logic as algae with:
72//!
73//! ```no_run
74//! use algae_cli::passphrases::{ExposeSecret, PassphraseArgs};
75//! use clap::Parser;
76//! use miette::Result;
77//!
78//! /// Your CLI tool
79//! #[derive(Parser)]
80//! struct Args {
81//! your_args: bool,
82//!
83//! #[command(flatten)]
84//! pass: PassphraseArgs,
85//! }
86//!
87//! #[tokio::main]
88//! async fn main() -> Result<()> {
89//! let args = Args::parse();
90//! let key = args.pass.require_phrase().await?;
91//! dbg!(key.expose_secret());
92//! Ok(())
93//! }
94//! ```
95//!
96//! Or you can add optional file encryption to a tool:
97//!
98//! ```no_run
99//! use std::path::PathBuf;
100//!
101//! use algae_cli::{keys::KeyArgs, streams::encrypt_stream};
102//! use clap::Parser;
103//! use miette::{IntoDiagnostic, Result, WrapErr};
104//! use tokio::fs::File;
105//! use tokio_util::compat::TokioAsyncWriteCompatExt;
106//!
107//! /// Your CLI tool
108//! ///
109//! /// If `--key` or `--key-path` is provided, the file will be encrypted.
110//! #[derive(Parser)]
111//! struct Args {
112//! output_path: PathBuf,
113//!
114//! #[command(flatten)]
115//! key: KeyArgs,
116//! }
117//!
118//! #[tokio::main]
119//! async fn main() -> Result<()> {
120//! let args = Args::parse();
121//!
122//! // if a key is provided, validate it early
123//! let key = args.key.get_public_key().await?;
124//!
125//! let mut input = generate_file_data_somehow().await;
126//! let mut output = File::create_new(args.output_path)
127//! .await
128//! .into_diagnostic()
129//! .wrap_err("opening the output file")?;
130//!
131//! if let Some(key) = key {
132//! encrypt_stream(input, output.compat_write(), key).await?;
133//! } else {
134//! tokio::io::copy(&mut input, &mut output)
135//! .await
136//! .into_diagnostic()
137//! .wrap_err("copying data to file")?;
138//! }
139//!
140//! Ok(())
141//! }
142//!
143//! # async fn generate_file_data_somehow() -> &'static [u8] { &[] }
144//! ```
145//!
146//! # The name
147//!
148//! _age_ is pronounced ah-gay. While [age doesn't have an inherent meaning](https://github.com/FiloSottile/age/discussions/329),
149//! the Italian-adjacent Friulian language (spoken around Venice) word _aghe_, pronounced the same, means water.
150//!
151//! Algae (pronounced al-gay or al-ghee) is a lightweight (a)ge. Algae are also fond of water.
152
153#![deny(missing_docs)]
154
155/// Clap argument parsers and implementations for the algae CLI functions.
156pub mod cli;
157
158/// Support for encrypting and decrypting files.
159pub mod files;
160
161/// Support for obtaining public and secret keys.
162pub mod keys;
163
164/// Support for obtaining passphrases.
165pub mod passphrases;
166
167/// Support for encrypting and decrypting bytestreams.
168pub mod streams;