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 age::secrecy::ExposeSecret;
75//! use algae_cli::passphrases::PassphraseArgs;
76//! use clap::Parser;
77//! use miette::Result;
78//!
79//! /// Your CLI tool
80//! #[derive(Parser)]
81//! struct Args {
82//!     your_args: bool,
83//!
84//!     #[command(flatten)]
85//!     pass: PassphraseArgs,
86//! }
87//!
88//! #[tokio::main]
89//! async fn main() -> Result<()> {
90//!     let args = Args::parse();
91//!     let key = args.pass.require_phrase().await?;
92//!     dbg!(key.expose_secret());
93//!     Ok(())
94//! }
95//! ```
96//!
97//! Or you can add optional file encryption to a tool:
98//!
99//! ```no_run
100//! use std::path::PathBuf;
101//!
102//! use algae_cli::{keys::KeyArgs, streams::encrypt_stream};
103//! use clap::Parser;
104//! use miette::{IntoDiagnostic, Result, WrapErr};
105//! use tokio::fs::File;
106//! use tokio_util::compat::TokioAsyncWriteCompatExt;
107//!
108//! /// Your CLI tool
109//! ///
110//! /// If `--key` or `--key-path` is provided, the file will be encrypted.
111//! #[derive(Parser)]
112//! struct Args {
113//!     output_path: PathBuf,
114//!
115//!     #[command(flatten)]
116//!     key: KeyArgs,
117//! }
118//!
119//! #[tokio::main]
120//! async fn main() -> Result<()> {
121//!     let args = Args::parse();
122//!
123//!     // if a key is provided, validate it early
124//!     let key = args.key.get_public_key().await?;
125//!
126//!     let mut input = generate_file_data_somehow().await;
127//!     let mut output = File::create_new(args.output_path)
128//!         .await
129//!         .into_diagnostic()
130//!         .wrap_err("opening the output file")?;
131//!
132//!     if let Some(key) = key {
133//!         encrypt_stream(input, output.compat_write(), key).await?;
134//!     } else {
135//!         tokio::io::copy(&mut input, &mut output)
136//!             .await
137//!             .into_diagnostic()
138//!             .wrap_err("copying data to file")?;
139//!     }
140//!
141//!     Ok(())
142//! }
143//!
144//! # async fn generate_file_data_somehow() -> &'static [u8] { &[] }
145//! ```
146//!
147//! # The name
148//!
149//! _age_ is pronounced ah-gay. While [age doesn't have an inherent meaning](https://github.com/FiloSottile/age/discussions/329),
150//! the Italian-adjacent Friulian language (spoken around Venice) word _aghe_, pronounced the same, means water.
151//!
152//! Algae (pronounced al-gay or al-ghee) is a lightweight (a)ge. Algae are also fond of water.
153
154#![deny(rust_2018_idioms)]
155#![deny(unsafe_code)]
156#![deny(missing_docs)]
157
158/// Clap argument parsers and implementations for the algae CLI functions.
159pub mod cli;
160
161/// Support for encrypting and decrypting files.
162pub mod files;
163
164/// Support for obtaining public and secret keys.
165pub mod keys;
166
167/// Support for obtaining passphrases.
168pub mod passphrases;
169
170/// Support for encrypting and decrypting bytestreams.
171pub mod streams;