### Rage CLI tool usage examples Source: https://context7.com/str4d/rage/llms.txt Command-line examples for generating keys, encrypting/decrypting files with recipients or passphrases, using ASCII armor, and integrating with SSH keys or plugins. ```bash # Generate a new key pair $ rage-keygen -o key.txt Public key: age1t7rxyev2z3rw82stdlrrepyc39nvn86l5078zqkf5uasdy86jp6svpy7pa ``` ```bash # Encrypt to a recipient key $ rage -r age1t7rxyev2z3rw82stdlrrepyc39nvn86l5078zqkf5uasdy86jp6svpy7pa \ -o secret.txt.age secret.txt ``` ```bash # Encrypt to multiple recipients (any one can decrypt) $ rage -r age1alice... -r age1bob... -o file.age file.txt ``` ```bash # Encrypt from a recipients file $ rage -R recipients.txt -o file.age file.txt ``` ```bash # Decrypt $ rage -d -i key.txt -o secret.txt secret.txt.age ``` ```bash # Encrypt with a passphrase (-p); auto-generates one if left empty $ rage -p -o secret.txt.age secret.txt Using an autogenerated passphrase: kiwi-general-undo-bubble-dwarf-dizzy-fame-side-sunset-sibling ``` ```bash # Encrypt with ASCII armor (PEM output) $ rage -a -r age1t7rxyev... -o secret.txt.age secret.txt ``` ```bash # Encrypt to an SSH public key; decrypt with private key $ rage -R ~/.ssh/id_ed25519.pub file.txt > file.txt.age $ rage -d -i ~/.ssh/id_ed25519 file.txt.age > file.txt ``` ```bash # Encrypt a passphrase-protected identity file (store key.txt remotely) $ rage -p -o key.age <(rage-keygen) $ rage -d -i key.age secret.txt.age > secret.txt ``` ```bash # Use a plugin identity (e.g. age-plugin-yubikey) $ rage -j yubikey -d encrypted.age > plaintext.txt ``` ```bash # Install rage $ cargo install rage $ brew install rage # macOS / Linux $ scoop install main/rage # Windows ``` -------------------------------- ### Install cargo-deb Source: https://github.com/str4d/rage/blob/main/docs/debian.md Install the cargo-deb tool, which is required for building Debian packages. ```bash cargo install cargo-deb ``` -------------------------------- ### Testing Localized Builds Source: https://github.com/str4d/rage/blob/main/docs/CONTRIBUTING.md Demonstrates how to run the rage binaries locally with a specific locale forced using the LANG environment variable. This is useful for testing translations before committing. ```bash $ LANG=your-locale cargo run --bin rage -- --help $ LANG=your-locale cargo run --bin rage -- ARGUMENTS $ LANG=your-locale cargo run --bin rage-keygen -- --help ``` -------------------------------- ### Build Debian Package Source: https://github.com/str4d/rage/blob/main/docs/debian.md Execute the cargo deb command to build the Debian package for the rage project. ```bash cargo deb --package rage ``` -------------------------------- ### Rage CLI Usage Source: https://github.com/str4d/rage/blob/main/README.md Displays the command-line interface usage for rage, outlining available commands, options, and arguments for encryption and decryption. ```bash Usage: rage [--encrypt] (-r RECIPIENT | -R PATH)... [-i IDENTITY] [-a] [-o OUTPUT] [INPUT] rage [--encrypt] --passphrase [-a] [-o OUTPUT] [INPUT] rage --decrypt [-i IDENTITY] [-o OUTPUT] [INPUT] Arguments: [INPUT] Path to a file to read from. Options: -h, --help Print this help message and exit. -V, --version Print version info and exit. -e, --encrypt Encrypt the input (the default). -d, --decrypt Decrypt the input. -p, --passphrase Encrypt with a passphrase instead of recipients. --max-work-factor Maximum work factor to allow for passphrase decryption. -a, --armor Encrypt to a PEM encoded format. -r, --recipient Encrypt to the specified RECIPIENT. May be repeated. -R, --recipients-file Encrypt to the recipients listed at PATH. May be repeated. -i, --identity Use the identity file at IDENTITY. May be repeated. -j Use age-plugin-PLUGIN-NAME in its default mode as an identity. -o, --output Write the result to the file at path OUTPUT. INPUT defaults to standard input, and OUTPUT defaults to standard output. If OUTPUT exists, it will be overwritten. RECIPIENT can be: - An age public key, as generated by rage-keygen ("age1..."). - An SSH public key ("ssh-ed25519 AAAA...", "ssh-rsa AAAA..."). PATH is a path to a file containing age recipients, one per line (ignoring "#" prefixed comments and empty lines). "-" may be used to read recipients from standard input. IDENTITY is a path to a file with age identities, one per line (ignoring "#" prefixed comments and empty lines), or to an SSH key file. Passphrase-encrypted age identity files can be used as identity files. Multiple identities may be provided, and any unused ones will be ignored. "-" may be used to read identities from standard input. ``` -------------------------------- ### Age Plugin Binary with Clap Argument Parsing Source: https://github.com/str4d/rage/blob/main/age-plugin/README.md This Rust code demonstrates how to create an age plugin binary. It uses `clap` to parse command-line arguments, specifically looking for the `--age-plugin` flag to determine if it should run as a plugin state machine. If not running as a plugin, it can be used for administrative tasks like key generation. ```rust use age_core::format::{FileKey, Stanza}; use age_plugin::{ identity::{self, IdentityPluginV1}, print_new_identity, recipient::{self, RecipientPluginV1}, Callbacks, run_state_machine, }; use clap::Parser; use std::collections::HashMap; use std::io; struct RecipientPlugin; impl RecipientPluginV1 for RecipientPlugin { fn add_recipient( &mut self, index: usize, plugin_name: &str, bytes: & [u8], ) -> Result<(), recipient::Error> { todo!() } fn add_identity( &mut self, index: usize, plugin_name: &str, bytes: & [u8] ) -> Result<(), recipient::Error> { todo!() } fn wrap_file_keys( &mut self, file_keys: Vec, mut callbacks: impl Callbacks, ) -> io::Result>, Vec>> { todo!() } } struct IdentityPlugin; impl IdentityPluginV1 for IdentityPlugin { fn add_identity( &mut self, index: usize, plugin_name: &str, bytes: & [u8] ) -> Result<(), identity::Error> { todo!() } fn unwrap_file_keys( &mut self, files: Vec>, mut callbacks: impl Callbacks, ) -> io::Result>>> { todo!() } } #[derive(Debug, Parser)] struct PluginOptions { #[arg(help = "run the given age plugin state machine", long)] age_plugin: Option, } fn main() -> io::Result<()> { let opts = PluginOptions::parse(); if let Some(state_machine) = opts.age_plugin { // The plugin was started by an age client; run the state machine. run_state_machine( &state_machine, Some(|| RecipientPlugin), Some(|| IdentityPlugin), )?; return Ok(()) } // Here you can assume the binary is being run directly by a user, // and perform administrative tasks like generating keys. Ok(()) } ``` -------------------------------- ### Encrypt and Decrypt with X25519 and Passphrase Source: https://context7.com/str4d/rage/llms.txt Demonstrates basic encryption and decryption using both X25519 keys and scrypt-based passphrases. Ensure 'age' is added to Cargo.toml. ```rust use age::secrecy::SecretString; fn main() -> Result<(), Box> { // --- Recipient-key encryption --- let identity = age::x25519::Identity::generate(); let recipient = identity.to_public(); let plaintext = b"Hello, age encryption!"; let ciphertext = age::encrypt(&recipient, plaintext)?; let decrypted = age::decrypt(&identity, &ciphertext)?; assert_eq!(decrypted, plaintext); // --- Passphrase encryption --- let passphrase = SecretString::from("correct horse battery staple".to_owned()); let pass_recipient = age::scrypt::Recipient::new(passphrase.clone()); let pass_identity = age::scrypt::Identity::new(passphrase); let ciphertext = age::encrypt(&pass_recipient, plaintext)?; let decrypted = age::decrypt(&pass_identity, &ciphertext)?; assert_eq!(decrypted, plaintext); Ok(()) } ``` -------------------------------- ### Fluent Localization String Format Source: https://github.com/str4d/rage/blob/main/docs/CONTRIBUTING.md Illustrates the basic and multiline string formats used in Fluent localization files. Ensure translations match the structure and paragraph breaks of the original English text. ```fluent some-unique-identifier = Translate the content on this side of the '=' symbol. another-unique-identifier = This is a multiline string that can contain one or more paragraphs. Like above, the 'another-unique-identifier =' part is not translated, but this text is. Individual paragraphs should be line-wrapped at roughly the same number of characters as the corresponding English text, so that it looks roughly the same. Remember that {-terms} and {$variables} won't necessarily be the same length once filled in. ``` -------------------------------- ### Encrypt File with Passphrase Source: https://github.com/str4d/rage/blob/main/README.md Encrypts a file using a passphrase. If no passphrase is provided, a secure one is automatically generated. Use '-o' to specify output file. ```bash $ rage -p -o example.png.age example.png Type passphrase (leave empty to autogenerate a secure one): [hidden] Using an autogenerated passphrase: kiwi-general-undo-bubble-dwarf-dizzy-fame-side-sunset-sibling ``` -------------------------------- ### `age::armor::ArmoredWriter` / `ArmoredReader` — ASCII armor I/O (feature: `armor`) Source: https://context7.com/str4d/rage/llms.txt Provides ASCII armor I/O capabilities for Age. `ArmoredWriter` wraps any `Write` and Base64-encodes the age binary ciphertext inside `-----BEGIN/END AGE ENCRYPTED FILE-----` markers. `ArmoredReader` transparently detects and decodes armored or raw age files from any `Read` source. ```APIDOC ## `age::armor::ArmoredWriter` / `ArmoredReader` — ASCII armor I/O (feature: `armor`) ### Description `ArmoredWriter` wraps any `Write` and Base64-encodes the age binary ciphertext inside `-----BEGIN/END AGE ENCRYPTED FILE-----` markers, for embedding in text-based contexts. `ArmoredReader` transparently detects and decodes armored or raw age files from any `Read` source. Both support `Seek` and async I/O when the `async` feature is enabled. ### Usage Example Encrypt with armor: ```rust use age::armor::{ArmoredWriter, Format}; use std::io::Write; use std::iter; let identity = age::x25519::Identity::generate(); let recipient = identity.to_public(); let plaintext = b"ASCII-armored encryption example"; let armored_ciphertext = { let encryptor = age::Encryptor::with_recipients(iter::once(&recipient as _)) .expect("recipient provided"); let mut output = Vec::new(); let armored_output = ArmoredWriter::wrap_output(&mut output, Format::AsciiArmor)?; let mut writer = encryptor.wrap_output(armored_output)?; writer.write_all(plaintext)?; // Must finish the StreamWriter first, then the ArmoredWriter writer.finish()?.finish()?; output }; let text = std::str::from_utf8(&armored_ciphertext)?; assert!(text.starts_with("-----BEGIN AGE ENCRYPTED FILE-----")); ``` Decrypt armored ciphertext: ```rust use age::armor::ArmoredReader; use std::io::Read; use std::iter; // Assuming armored_ciphertext is available from the encryption step let decrypted = { // ArmoredReader auto-detects armored vs. binary let armored_reader = ArmoredReader::new(&armored_ciphertext[..]); let decryptor = age::Decryptor::new(armored_reader)?; let mut reader = decryptor.decrypt(iter::once(&identity as _))?; let mut out = Vec::new(); reader.read_to_end(&mut out)?; out }; assert_eq!(decrypted, plaintext); ``` ``` -------------------------------- ### ASCII Armor I/O for Age Encryption Source: https://context7.com/str4d/rage/llms.txt Wraps any `Write` and Base64-encodes age binary ciphertext inside `-----BEGIN/END AGE ENCRYPTED FILE-----` markers for text-based contexts. `ArmoredReader` transparently detects and decodes armored or raw age files from any `Read` source. ```rust use age::armor::{ArmoredReader, ArmoredWriter, Format}; use std::io::{Read, Write}; use std::iter; fn main() -> Result<(), Box> { let identity = age::x25519::Identity::generate(); let recipient = identity.to_public(); let plaintext = b"ASCII-armored encryption example"; // --- Encrypt with armor --- let armored_ciphertext = { let encryptor = age::Encryptor::with_recipients(iter::once(&recipient as _)) .expect("recipient provided"); let mut output = Vec::new(); let armored_output = ArmoredWriter::wrap_output(&mut output, Format::AsciiArmor)?; let mut writer = encryptor.wrap_output(armored_output)?; writer.write_all(plaintext)?; // Must finish the StreamWriter first, then the ArmoredWriter writer.finish()?.finish()?; output }; // The output starts with the armor header let text = std::str::from_utf8(&armored_ciphertext)?; assert!(text.starts_with("-----BEGIN AGE ENCRYPTED FILE-----")); // --- Decrypt armored ciphertext --- let decrypted = { // ArmoredReader auto-detects armored vs. binary let armored_reader = ArmoredReader::new(&armored_ciphertext[..]); let decryptor = age::Decryptor::new(armored_reader)?; let mut reader = decryptor.decrypt(iter::once(&identity as _))?; let mut out = Vec::new(); reader.read_to_end(&mut out)?; out }; assert_eq!(decrypted, plaintext); Ok(()) } ``` -------------------------------- ### Control scrypt work factor for testing Source: https://context7.com/str4d/rage/llms.txt Manually set the scrypt work factor for testing or specific security/performance needs. Use `set_max_work_factor` to cap decryption costs and prevent DoS attacks. ```rust use age::secrecy::SecretString; use std::io::{Read, Write}; use std::iter; fn main() -> Result<(), Box> { let passphrase = SecretString::from("test".to_owned()); // --- Encrypt with a controlled (fast) work factor for testing --- let mut recipient = age::scrypt::Recipient::new(passphrase.clone()); recipient.set_work_factor(10); // N=1024, very fast, NOT production-safe let encryptor = age::Encryptor::with_recipients(iter::once(&recipient as _)).unwrap(); let mut ciphertext = Vec::new(); let mut writer = encryptor.wrap_output(&mut ciphertext)?; writer.write_all(b"fast test")?; writer.finish()?; // --- Decrypt with a capped max work factor --- let mut identity = age::scrypt::Identity::new(passphrase); identity.set_max_work_factor(20); // refuse to spend > ~16s on decryption let decryptor = age::Decryptor::new(&ciphertext[..])?; let mut reader = decryptor.decrypt(iter::once(&identity as _))?; let mut out = Vec::new(); reader.read_to_end(&mut out)?; assert_eq!(out, b"fast test"); Ok(()) } ``` -------------------------------- ### Encrypt and Decrypt with SSH Keys Source: https://context7.com/str4d/rage/llms.txt Demonstrates parsing an SSH public key as an age recipient and an OpenSSH private key as an age identity for encryption and decryption. Requires the 'ssh' feature for the age crate. ```rust use std::io::{BufReader, Read}; use std::iter; fn main() -> Result<(), Box> { // Parse an ssh-ed25519 public key as an age recipient let pub_key_line = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBzLtXlk9kKf7NuQJ7MRMB7Rr0tE+smY2QQHLL2uBsJ2 user@host"; let recipient: age::ssh::Recipient = pub_key_line.parse()?; let plaintext = b"Encrypted to an SSH public key"; let ciphertext = age::encrypt(&recipient, plaintext)?; // Parse an OpenSSH private key as an age identity (handles encrypted keys too) let private_key_pem = include_str!("~/.ssh/id_ed25519"); // PEM content let identity = age::ssh::Identity::from_buffer( BufReader::new(private_key_pem.as_bytes()), None, // optional filename for error messages )?; let decryptor = age::Decryptor::new(&ciphertext[..])?; let mut reader = decryptor.decrypt(iter::once(&identity as &dyn age::Identity))?; let mut decrypted = Vec::new(); reader.read_to_end(&mut decrypted)?; assert_eq!(decrypted, plaintext); Ok(()) } ``` -------------------------------- ### age::Encryptor::with_user_passphrase Source: https://context7.com/str4d/rage/llms.txt Creates an Encryptor that encrypts data using a passphrase. The encryption uses scrypt for key derivation, calibrated to take approximately 1 second. This method is for passphrase-only encryption and cannot be combined with other recipient types. ```APIDOC ## age::Encryptor::with_user_passphrase ### Description Creates an `Encryptor` that encrypts with a scrypt-derived key from a human-supplied passphrase. The scrypt work factor is automatically calibrated to take approximately 1 second on the current device. A passphrase-encrypted file cannot be combined with other recipient types. ### Method Signature `Encryptor::with_user_passphrase(passphrase: impl Into) -> Encryptor` ### Parameters * `passphrase`: The passphrase to use for encryption, provided as a `SecretString` or a type that can be converted into it. ### Usage Example ```rust use age::secrecy::SecretString; use std::io::{Read, Write}; use std::iter; let passphrase = SecretString::from("my-secret-passphrase".to_owned()); let plaintext = b"Protected by passphrase"; // Encrypt let ciphertext = { let encryptor = age::Encryptor::with_user_passphrase(passphrase.clone()); let mut buf = Vec::new(); let mut writer = encryptor.wrap_output(&mut buf)?; writer.write_all(plaintext)?; writer.finish()?; buf }; // Decrypt let decrypted = { let decryptor = age::Decryptor::new(&ciphertext[..])?; // Verify this file is passphrase-encrypted before prompting the user assert!(decryptor.is_scrypt()); let identity = age::scrypt::Identity::new(passphrase); let mut out = Vec::new(); let mut reader = decryptor.decrypt(iter::once(&identity as _))?; reader.read_to_end(&mut out)?; out }; assert_eq!(decrypted, plaintext); ``` ``` -------------------------------- ### Encrypt with Passphrase-Protected Identity Source: https://github.com/str4d/rage/blob/main/README.md Encrypts a file using a passphrase-protected identity file. The identity file is automatically decrypted before use. You will be prompted for the identity file's passphrase. ```bash $ rage -p -o key.age <(rage-keygen) Public key: age1pymw5hyr39qyuc950tget63aq8vfd52dclj8x7xhm08g6ad86dkserumnz Type passphrase (leave empty to autogenerate a secure one): [hidden] Using an autogenerated passphrase: flash-bean-celery-network-curious-flower-salt-amateur-fence-giant ``` ```bash $ rage -r age1pymw5hyr39qyuc950tget63aq8vfd52dclj8x7xhm08g6ad86dkserumnz secrets.txt > secrets.txt.age ``` ```bash $ rage -d -i key.age secrets.txt.age > secrets.txt Type passphrase: [hidden] ``` -------------------------------- ### SSH Key Encryption Source: https://context7.com/str4d/rage/llms.txt Demonstrates how to parse SSH public keys as age recipients and encrypt data using them. It also shows how to parse OpenSSH private keys as age identities for decryption. ```APIDOC ## `age::ssh::Recipient` / `age::ssh::Identity` — SSH key encryption (feature: `ssh`) Allows reusing existing `ssh-ed25519` and `ssh-rsa` SSH key files for age encryption. Note: SSH-based recipients are **not anonymous** — encrypted files embed a 4-byte fingerprint of the public key. Prefer native X25519 keys for new use cases. Requires `age = { version = "0.11", features = ["ssh"] }`. ### Usage Example ```rust use std::io::{BufReader, Read}; use std::iter; fn main() -> Result<(), Box> { // Parse an ssh-ed25519 public key as an age recipient let pub_key_line = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBzLtXlk9kKf7NuQJ7MRMB7Rr0tE+smY2QQHLL2uBsJ2 user@host"; let recipient: age::ssh::Recipient = pub_key_line.parse()?; let plaintext = b"Encrypted to an SSH public key"; let ciphertext = age::encrypt(&recipient, plaintext)?; // Parse an OpenSSH private key as an age identity (handles encrypted keys too) let private_key_pem = include_str!("~/.ssh/id_ed25519"); // PEM content let identity = age::ssh::Identity::from_buffer( BufReader::new(private_key_pem.as_bytes()), None, // optional filename for error messages )?; let decryptor = age::Decryptor::new(&ciphertext[..])?; let mut reader = decryptor.decrypt(iter::once(&identity as &dyn age::Identity))?; let mut decrypted = Vec::new(); reader.read_to_end(&mut decrypted)?; assert_eq!(decrypted, plaintext); Ok(()) } ``` ``` -------------------------------- ### Recipient File Format Source: https://github.com/str4d/rage/blob/main/README.md Defines the format for recipient files used with the -R flag. Each line should contain one age recipient public key, with support for comments and blank lines. ```text # Alice age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p ``` -------------------------------- ### Decrypt Passphrase-Encrypted Age Identity Source: https://context7.com/str4d/rage/llms.txt Shows how to wrap a passphrase-encrypted age identity file for decryption. The passphrase is provided via a custom `Callbacks` implementation. Requires the 'armor' feature if the identity file is armored. ```rust use age::{Callbacks, NoCallbacks}; use age::secrecy::SecretString; use std::io::Read; // A Callbacks impl that provides the passphrase programmatically #[derive(Clone)] struct StaticPassphrase(&'static str); impl Callbacks for StaticPassphrase { fn display_message(&self, _: &str) {} fn confirm(&self, _: &str, _: &str, _: Option<&str>) -> Option { None } fn request_public_string(&self, _: &str) -> Option { None } fn request_passphrase(&self, _: &str) -> Option { Some(SecretString::from(self.0.to_owned())) } } fn main() -> Result<(), Box> { // Read an armored, passphrase-encrypted age identity file #[cfg(feature = "armor")] { use age::armor::ArmoredReader; use std::iter; let encrypted_identity_pem: &[u8] = b"-----BEGIN AGE ENCRYPTED FILE-----\n..."; let identity = age::encrypted::Identity::from_buffer( ArmoredReader::new(encrypted_identity_pem), None, // optional filename StaticPassphrase("my-passphrase"), // callbacks None, // optional max_work_factor )? .expect("this is a passphrase-encrypted age file"); // identity implements age::Identity; passphrase is requested on first use let pk: age::x25519::Recipient = "age1t7rxyev2z3rw82stdlrrepyc39nvn86l5078zqkf5uasdy86jp6svpy7pa".parse()?; let ciphertext = age::encrypt(&pk, b"hello")?; let decryptor = age::Decryptor::new(&ciphertext[..])?; let mut reader = decryptor.decrypt(iter::once(&identity as &dyn age::Identity))?; let mut out = Vec::new(); reader.read_to_end(&mut out)?; } Ok(()) } ``` -------------------------------- ### Passphrase-Encrypted Identity Files Source: https://context7.com/str4d/rage/llms.txt Explains how to use passphrase-encrypted age identity files, which wrap an age identity within an age ciphertext. This is useful for securing identity files stored remotely. ```APIDOC ## `age::encrypted::Identity` — Passphrase-encrypted identity files Wraps a passphrase-encrypted age identity file (an age ciphertext containing another age identity). Used when identity files are stored remotely or require additional protection. The decryption result is cached in-memory after the first use, so the passphrase callback is only triggered once. ### Usage Example ```rust use age::{Callbacks, NoCallbacks}; use age::secrecy::SecretString; use std::io::Read; // A Callbacks impl that provides the passphrase programmatically #[derive(Clone)] struct StaticPassphrase(&'static str); impl Callbacks for StaticPassphrase { fn display_message(&self, _: &str) {} fn confirm(&self, _: &str, _: &str, _: Option<&str>) -> Option { None } fn request_public_string(&self, _: &str) -> Option { None } fn request_passphrase(&self, _: &str) -> Option { Some(SecretString::from(self.0.to_owned())) } } fn main() -> Result<(), Box> { // Read an armored, passphrase-encrypted age identity file #[cfg(feature = "armor")] { use age::armor::ArmoredReader; use std::iter; let encrypted_identity_pem: &[u8] = b"-----BEGIN AGE ENCRYPTED FILE-----\n..."; let identity = age::encrypted::Identity::from_buffer( ArmoredReader::new(encrypted_identity_pem), None, // optional filename StaticPassphrase("my-passphrase"), // callbacks None, // optional max_work_factor )? .expect("this is a passphrase-encrypted age file"); // identity implements age::Identity; passphrase is requested on first use let pk: age::x25519::Recipient = "age1t7rxyev2z3rw82stdlrrepyc39nvn86l5078zqkf5uasdy86jp6svpy7pa".parse()?; let ciphertext = age::encrypt(&pk, b"hello")?; let decryptor = age::Decryptor::new(&ciphertext[..])?; let mut reader = decryptor.decrypt(iter::once(&identity as &dyn age::Identity))?; let mut out = Vec::new(); reader.read_to_end(&mut out)?; } Ok(()) } ``` ``` -------------------------------- ### Encrypt and Armor to ASCII Text Source: https://context7.com/str4d/rage/llms.txt Encrypts data and wraps the ciphertext in a PEM-style ASCII armor block. Requires the 'armor' feature flag. The 'age::decrypt' function can handle both raw and armored ciphertexts when 'armor' is enabled. ```rust use age::secrecy::SecretString; fn main() -> Result<(), Box> { let identity = age::x25519::Identity::generate(); let recipient = identity.to_public(); let plaintext = b"Secrets stored as text"; // Encrypt and armor let armored: String = age::encrypt_and_armor(&recipient, plaintext)?; assert!(armored.starts_with("-----BEGIN AGE ENCRYPTED FILE-----")); println!("{}", armored); // -----BEGIN AGE ENCRYPTED FILE----- // YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+... // -----END AGE ENCRYPTED FILE----- // Decrypt (age::decrypt handles both armored and raw ciphertext when // the `armor` feature is enabled) let decrypted = age::decrypt(&identity, armored.as_bytes())?; assert_eq!(decrypted, plaintext); Ok(()) } ``` -------------------------------- ### Generate and Parse X25519 Key Pair Source: https://context7.com/str4d/rage/llms.txt Generates a new X25519 identity (secret key) and derives the corresponding recipient (public key). Demonstrates serialization and parsing of keys using Display and FromStr traits. Secret keys are wrapped in SecretString to prevent accidental logging. ```rust use age::secrecy::ExposeSecret; fn main() { // Generate a new key let identity = age::x25519::Identity::generate(); let recipient = identity.to_public(); // Secret key is wrapped in SecretString to prevent accidental logging println!("Public key: {}", recipient); // Public key: age1t7rxyev2z3rw82stdlrrepyc39nvn86l5078zqkf5uasdy86jp6svpy7pa println!("Secret key: {}", identity.to_string().expose_secret()); // Secret key: AGE-SECRET-KEY-1GQ9778VQXMMJVE8SK7J6VT8UJ4HDQAJUVSFCWCM02D8GEWQ72PVQ2Y5J33 // Parse existing keys from strings let sk: age::x25519::Identity = "AGE-SECRET-KEY-1GQ9778VQXMMJVE8SK7J6VT8UJ4HDQAJUVSFCWCM02D8GEWQ72PVQ2Y5J33" .parse() .expect("valid secret key"); let pk: age::x25519::Recipient = "age1t7rxyev2z3rw82stdlrrepyc39nvn86l5078zqkf5uasdy86jp6svpy7pa" .parse() .expect("valid public key"); // Verify the pair matches assert_eq!(sk.to_public().to_string(), pk.to_string()); } ``` -------------------------------- ### age::encrypt_and_armor Source: https://context7.com/str4d/rage/llms.txt Encrypts a plaintext byte slice and wraps the binary ciphertext in a PEM-style ASCII armor block, returning a String. Useful when the ciphertext must be embedded in text files, emails, or configs. ```APIDOC ## age::encrypt_and_armor ### Description Encrypts a plaintext byte slice and wraps the binary ciphertext in a PEM-style ASCII armor block (`-----BEGIN AGE ENCRYPTED FILE-----`), returning a `String`. Useful when the ciphertext must be embedded in text files, emails, or configs. ### Method ```rust fn encrypt_and_armor(recipient: &impl Recipient, plaintext: &[u8]) -> Result ``` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```rust use age::secrecy::SecretString; fn main() -> Result<(), Box> { let identity = age::x25519::Identity::generate(); let recipient = identity.to_public(); let plaintext = b"Secrets stored as text"; // Encrypt and armor let armored: String = age::encrypt_and_armor(&recipient, plaintext)?; assert!(armored.starts_with("-----BEGIN AGE ENCRYPTED FILE-----\n")); println!("{}", armored); // -----BEGIN AGE ENCRYPTED FILE----- // YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+... // -----END AGE ENCRYPTED FILE----- // Decrypt (age::decrypt handles both armored and raw ciphertext when // the `armor` feature is enabled) let decrypted = age::decrypt(&identity, armored.as_bytes())?; assert_eq!(decrypted, plaintext); Ok(()) } ``` ### Response #### Success Response (200) - **armored** (String) - The ASCII-armored ciphertext. ``` -------------------------------- ### Add age Dependency to Cargo.toml Source: https://github.com/str4d/rage/blob/main/age/README.md Add this line to your Cargo.toml file to include the age library in your Rust project. ```toml age = "0.11" ``` -------------------------------- ### Encrypt with Passphrase using age Source: https://context7.com/str4d/rage/llms.txt Encrypts data using a passphrase derived key. This method is for single-recipient encryption and cannot be combined with other recipient types. ```rust use age::secrecy::SecretString; use std::io::{Read, Write}; use std::iter; fn main() -> Result<(), Box> { let passphrase = SecretString::from("my-secret-passphrase".to_owned()); let plaintext = b"Protected by passphrase"; // Encrypt let ciphertext = { let encryptor = age::Encryptor::with_user_passphrase(passphrase.clone()); let mut buf = Vec::new(); let mut writer = encryptor.wrap_output(&mut buf)?; writer.write_all(plaintext)?; writer.finish()?; buf }; // Decrypt let decrypted = { let decryptor = age::Decryptor::new(&ciphertext[..])?; // Verify this file is passphrase-encrypted before prompting the user assert!(decryptor.is_scrypt()); let identity = age::scrypt::Identity::new(passphrase); let mut out = Vec::new(); let mut reader = decryptor.decrypt(iter::once(&identity as _))?; reader.read_to_end(&mut out)?; out }; assert_eq!(decrypted, plaintext); Ok(()) } ``` -------------------------------- ### Decrypt File with Passphrase Source: https://github.com/str4d/rage/blob/main/README.md Decrypts a file that was encrypted with a passphrase. You will be prompted to enter the passphrase. ```bash $ rage -d example.png.age >example.png Type passphrase: [hidden] ``` -------------------------------- ### Encrypt File with Recipients Source: https://github.com/str4d/rage/blob/main/README.md Encrypts a file using a list of recipients specified in a file. Reads recipients from standard input if '-' is used. ```bash $ rage -R recipients.txt example.jpg > example.jpg.age ``` -------------------------------- ### Encrypt to Multiple Recipients Source: https://github.com/str4d/rage/blob/main/README.md Encrypts a file to multiple recipients by specifying each recipient's public key using the -r flag. Each listed recipient can decrypt the file. ```bash $ rage -o example.png.age -r age1uvscypafkkxt6u2gkguxet62cenfmnpc0smzzlyun0lzszfatawq4kvf2u \ -r age1ex4ty8ppg02555at009uwu5vlk5686k3f23e7mac9z093uvzfp8sxr5jum example.png ``` -------------------------------- ### Encrypt with SSH Public Key Source: https://github.com/str4d/rage/blob/main/README.md Encrypts a file using an SSH public key. The public key is embedded in the encrypted file. ```bash $ rage -R ~/.ssh/id_ed25519.pub example.png > example.png.age ``` -------------------------------- ### Export Recipients File from Identities Source: https://context7.com/str4d/rage/llms.txt Writes a recipients file (one public `age1...` key per line) from the identities loaded in an `IdentityFile`. Useful for sharing the public-key counterpart of an identity file with senders. ```rust use std::io::BufReader; fn main() -> Result<(), Box> { let key_data = "AGE-SECRET-KEY-1GQ9778VQXMMJVE8SK7J6VT8UJ4HDQAJUVSFCWCM02D8GEWQ72PVQ2Y5J33\n"; let id_file = age::IdentityFile::from_buffer(BufReader::new(key_data.as_bytes()))?; let mut recipients_output = Vec::new(); id_file.write_recipients_file(&mut recipients_output)?; let recipients_str = String::from_utf8(recipients_output)?; println!("{}", recipients_str); // age1t7rxyev2z3rw82stdlrrepyc39nvn86l5078zqkf5uasdy86jp6svpy7pa Ok(()) } ``` -------------------------------- ### age::Decryptor::new / new_buffered Source: https://context7.com/str4d/rage/llms.txt Parses the age file header from a Read source to create a Decryptor. `new_buffered` is optimized for BufRead sources. After initialization, use the `decrypt` method with an iterator of `Identity` objects to obtain a `StreamReader` for the plaintext. ```APIDOC ## age::Decryptor::new / new_buffered ### Description `Decryptor::new` parses the age file header from any `Read` source; `new_buffered` is more efficient for `BufRead` sources (including `&[u8]` slices). After construction, call `decrypt(identities)` with an iterator of `Identity` objects to obtain a `StreamReader` for reading the plaintext. ### Method Signatures * `Decryptor::new(reader: impl Read) -> Result` * `Decryptor::new_buffered(reader: impl BufRead) -> Result` ### Parameters * `reader`: A source implementing `Read` or `BufRead` from which to read the ciphertext. ### Usage Example ```rust use std::io::Read; use std::iter; fn decrypt_file( ciphertext: &[u8], identity: &age::x25519::Identity, ) -> Result, age::DecryptError> { // new_buffered is preferred for in-memory slices let decryptor = age::Decryptor::new_buffered(ciphertext)?; match decryptor.decrypt(iter::once(identity as &dyn age::Identity)) { Ok(mut reader) => { let mut plaintext = Vec::new(); reader.read_to_end(&mut plaintext)?; Ok(plaintext) } Err(age::DecryptError::NoMatchingKeys) => { eprintln!("None of the provided identities could decrypt the file."); Err(age::DecryptError::NoMatchingKeys) } Err(age::DecryptError::ExcessiveWork { required, target }) => { eprintln!( "Passphrase work factor too high: required={}, device_target={}", required, target ); Err(age::DecryptError::ExcessiveWork { required, target }) } Err(e) => Err(e), } } fn main() -> Result<(), Box> { let key = age::x25519::Identity::generate(); let ciphertext = age::encrypt(&key.to_public(), b"test")?; let plaintext = decrypt_file(&ciphertext, &key)?; assert_eq!(plaintext, b"test"); Ok(()) } ``` ``` -------------------------------- ### `age::IdentityFile` — Parse identity files Source: https://context7.com/str4d/rage/llms.txt Parses one or more age identities from a file or buffer. The resulting identities can be used for decryption. File size is limited to 16 MiB. ```APIDOC ## `age::IdentityFile` — Parse identity files ### Description Parses one or more age identities from a file or buffer containing lines in the standard age identity file format (one `AGE-SECRET-KEY-1...` per line, with `#` comments and blank lines ignored). The resulting identities implement the `Identity` trait for decryption. File size is limited to 16 MiB. ### Usage Examples Parse from a file on disk: ```rust let id_file = age::IdentityFile::from_file("~/.age/key.txt".to_owned()); ``` Parse from an in-memory buffer: ```rust use std::io::BufReader; let key_data = "# My age key\nAGE-SECRET-KEY-1GQ9778VQXMMJVE8SK7J6VT8UJ4HDQAJUVSFCWCM02D8GEWQ72PVQ2Y5J33\n"; let id_file = age::IdentityFile::from_buffer(BufReader::new(key_data.as_bytes()))?; ``` Convert to a list of Box and use for decryption: ```rust let identities = id_file.into_identities()?; let pk: age::x25519::Recipient = "age1t7rxyev2z3rw82stdlrrepyc39nvn86l5078zqkf5uasdy86jp6svpy7pa" .parse()?; let ciphertext = age::encrypt(&pk, b"hello")?; let decryptor = age::Decryptor::new(&ciphertext[..])?; let mut reader = decryptor.decrypt(identities.iter().map(|i| i.as_ref() as _))?; let mut plaintext = Vec::new(); reader.read_to_end(&mut plaintext)?; assert_eq!(plaintext, b"hello"); ``` ``` -------------------------------- ### Parse age Identity Files Source: https://context7.com/str4d/rage/llms.txt Parses one or more age identities from a file or buffer. Supports standard age identity file format with comments and blank lines ignored. File size is limited to 16 MiB. ```rust use std::io::{BufReader, Read}; use std::iter; fn main() -> Result<(), Box> { // Parse from a file on disk let id_file = age::IdentityFile::from_file("~/.age/key.txt".to_owned()); // Parse from an in-memory buffer let key_data = "# My age key\nAGE-SECRET-KEY-1GQ9778VQXMMJVE8SK7J6VT8UJ4HDQAJUVSFCWCM02D8GEWQ72PVQ2Y5J33\n"; let id_file = age::IdentityFile::from_buffer(BufReader::new(key_data.as_bytes()))?; // Convert to a list of Box let identities = id_file.into_identities()?; println!("Loaded {} identity/identities", identities.len()); // Use for decryption let pk: age::x25519::Recipient = "age1t7rxyev2z3rw82stdlrrepyc39nvn86l5078zqkf5uasdy86jp6svpy7pa" .parse()?; let ciphertext = age::encrypt(&pk, b"hello")?; let decryptor = age::Decryptor::new(&ciphertext[..])?; let mut reader = decryptor.decrypt(identities.iter().map(|i| i.as_ref() as _))?; let mut plaintext = Vec::new(); reader.read_to_end(&mut plaintext)?; assert_eq!(plaintext, b"hello"); Ok(()) } ``` -------------------------------- ### Encrypt to Multiple Recipients with age Source: https://context7.com/str4d/rage/llms.txt Encrypts data for multiple recipients simultaneously. Ensure `StreamWriter::finish()` is called to finalize the ciphertext. ```rust use std::io::{Read, Write}; use std::iter; fn main() -> Result<(), Box> { let alice = age::x25519::Identity::generate(); let bob = age::x25519::Identity::generate(); let recipients: &[&dyn age::Recipient] = & [ &alice.to_public(), &bob.to_public(), ]; let plaintext = b"Encrypted for Alice AND Bob"; // Encrypt let ciphertext = { let encryptor = age::Encryptor::with_recipients(recipients.iter().copied()) .expect("non-empty recipient list"); let mut ciphertext = Vec::new(); let mut writer = encryptor.wrap_output(&mut ciphertext)?; writer.write_all(plaintext)?; writer.finish()?; // MUST be called ciphertext }; // Either identity can decrypt for identity in [&alice, &bob] { let decryptor = age::Decryptor::new(&ciphertext[..])?; let mut plaintext_out = Vec::new(); let mut reader = decryptor.decrypt(iter::once(identity as &dyn age::Identity))?; reader.read_to_end(&mut plaintext_out)?; assert_eq!(plaintext_out, plaintext); } Ok(()) } ```