algae_cli/
lib.rs

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

#![deny(rust_2018_idioms)]
#![deny(unsafe_code)]
#![deny(missing_docs)]

/// Clap argument parsers and implementations for the algae CLI functions.
pub mod cli;

/// Support for encrypting and decrypting files.
pub mod files;

/// Support for obtaining public and secret keys.
pub mod keys;

/// Support for obtaining passphrases.
pub mod passphrases;

/// Support for encrypting and decrypting bytestreams.
pub mod streams;