age-setup
Simple, secure X25519 keypair generation for age encryption — with validation and automatic memory zeroization.
Table of Contents
- Features
- Installation
- Quick Start
- Usage Examples
- API Reference
- Security Features
- Development
- Contributing
- License
- Credits
Features
Simple API — One function call generates a complete keypair
Secure by Default — Automatic memory zeroization on drop
Validated Keys — Public keys guaranteed to start with "age1"
️ Privacy-First — Secret keys redacted in Display output
Zero Config — Works out of the box with sensible defaults
Well-Tested — Comprehensive test coverage across all modules
Fast — Built on the battle-tested age crate
Documented — Full API documentation with examples
Installation
Add age-setup to your Cargo.toml:
[]
= "0.1"
Or use cargo add:
Minimum Supported Rust Version (MSRV): 1.70.0
Quick Start
Generate an age keypair in just two lines:
use build_keypair;
That's it! You now have a cryptographically secure X25519 keypair ready for age encryption.
Usage Examples
Basic Key Generation
The simplest way to generate a keypair:
use build_keypair;
let keypair = build_keypair.expect;
// Public key is validated and guaranteed to start with "age1"
assert!;
// Use the keys with age encryption
println!;
Error Handling
Handle different error types explicitly:
use ;
match build_keypair
Accessing Keys
use build_keypair;
let keypair = build_keypair?;
// Public key (safe to display)
let public_str: &str = keypair.public.expose;
let public_owned: String = keypair.public.to_string;
// Secret key (handle with care!)
let secret_str: &str = keypair.secret.expose;
// Convert to AsRef<str> for compatibility
print_key;
// Secret is automatically zeroized when dropped
// <-- Memory is securely wiped here
Integration with age Encryption
use build_keypair;
use Write;
let keypair = build_keypair?;
// Encrypt a file with age
let encrypted = encrypt?;
// Save the secret key securely
let key_path = home_dir.unwrap.join;
write?;
// Set restrictive permissions (Unix only)
API Reference
Functions
build_keypair()
Generates a new age X25519 keypair.
Returns:
Ok(KeyPair)— A new keypair with validated public keyErr(Error)— If generation or validation fails
Example:
let keypair = build_keypair?;
Types
KeyPair
A keypair consisting of an age public key and its corresponding secret key.
Fields:
public: PublicKey— The public key (starts with "age1")secret: SecretKey— The secret key (zeroized on drop)
Example:
let keypair = build_keypair?;
println!;
println!; // Prints: [REDACTED]
PublicKey
An age public key, guaranteed to start with "age1".
;
Methods:
expose(&self) -> &str
Returns the raw string representation of the public key.
let public_str = keypair.public.expose;
assert!;
Traits Implemented:
Display— Prints the public keyDebug— Debug representationClone— Can be cloned safelyAsRef<str>— Convert to string reference
SecretKey
An age secret key that securely wipes its memory when dropped.
Methods:
expose(&self) -> &str
Exposes the raw secret key as a string.
️Security Warning: Only use this when absolutely necessary, as it exposes the secret.
let secret_str = keypair.secret.expose;
// Use secret_str with caution!
Traits Implemented:
Display— Prints[REDACTED]instead of the actual secretDebug— Debug representation (does not expose secret)Clone— Can be cloned (new copy is also zeroized on drop)Drop— Automatically zeroizes memory when dropped
Error Types
Error
Main error type for the crate.
Variants:
Error::Generation
Error during key generation (e.g., internal library failure).
Error::Validation
Error validating public key format.
Example:
use PublicKey;
let result = new;
assert!; // Does not start with "age1"
Error::Security
Error during security operations (e.g., memory wipe).
All errors implement:
std::error::Error— Standard error traitDisplay— Human-readable error messagesDebug— Detailed debug information
Security Features
Memory Zeroization
The SecretKey type automatically zeroes its memory when dropped, preventing secrets from lingering in RAM.
// <-- Memory is securely overwritten with zeros here
Implementation:
- Uses the
zeroizecrate - Compiler optimizations cannot remove the zeroing operation
- Applies to both the original and cloned instances
Display Redaction
Secret keys are automatically redacted when printed:
let keypair = build_keypair?;
println!; // Prints: [REDACTED]
println!; // Prints: SecretKey { ... }
// Only expose() shows the actual secret
println!; // Prints actual key
This prevents accidental logging or display of sensitive material.
Public Key Validation
All public keys are validated to ensure they start with the "age1" prefix:
use PublicKey;
// Valid key
let valid = new?;
// Invalid key (will return error)
let invalid = new;
assert!;
Validation Rules:
- Must not be empty
- Must start with "age1"
- Automatically applied during keypair generation
Development
Project Structure
age-setup/
├── src/
│ ├── apis/
│ │ ├── build.rs # Keypair building API
│ │ └── mod.rs
│ ├── build/
│ │ ├── identity.rs # Internal identity generation
│ │ ├── recipient.rs # Recipient extraction
│ │ └── mod.rs
│ ├── errors/
│ │ ├── buildings.rs # Generation errors
│ │ ├── security.rs # Security errors
│ │ ├── validation.rs # Validation errors
│ │ └── mod.rs
│ ├── security/
│ │ ├── zeroize.rs # Memory zeroization utilities
│ │ └── mod.rs
│ ├── types/
│ │ ├── keypair.rs # KeyPair structure
│ │ ├── public_key.rs # PublicKey type
│ │ ├── secret_key.rs # SecretKey type
│ │ ├── validation.rs # Validation logic
│ │ └── mod.rs
│ └── lib.rs # Library entry point
├── benches/
│ └── keygen.rs # Benchmarks
├── Cargo.toml
└── README.md
Building
# Clone the repository
# Build the library
# Build with optimizations
# Build documentation
Testing
The library has comprehensive test coverage across all modules.
# Run all tests
# Run tests with output
# Run tests for a specific module
# Run tests with coverage (requires cargo-tarpaulin)
Test Coverage:
- Keypair generation
- Public key validation
- Secret key zeroization
- Display implementations
- Error handling
- Type conversions
Benchmarking
Performance benchmarks are available using Criterion:
# Run benchmarks
# Run specific benchmark
# Generate benchmark report
Benchmark Results (example on Apple M1):
keygen/build_keypair time: [45.2 µs 45.8 µs 46.5 µs]
Contributing
Contributions are welcome! Here's how you can help:
-
Fork the repository
-
Create a feature branch
-
Make your changes
- Write tests for new functionality
- Ensure all tests pass:
cargo test - Format code:
cargo fmt - Run clippy:
cargo clippy
-
Commit your changes
Use Conventional Commits format:
feat:— New featurefix:— Bug fixdocs:— Documentation changestest:— Test additions/changesrefactor:— Code refactoring
-
Push and create a Pull Request
Code of Conduct
Please be respectful and constructive in all interactions. We're here to build great software together.
License
MIT License — see LICENSE for details.
This library is free to use in both open-source and commercial projects.
Copyright (c) 2026 neuxdotdev
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
Credits
- Built on the excellent
agecrate by @str4d - Uses
zeroizefor secure memory handling - Inspired by the simplicity of the age specification
Related Projects
- age — A simple, modern, and secure file encryption tool
- rage — A Rust implementation of age
- age-plugin — Framework for age plugins
FAQ
Why use this instead of calling age directly?
age-setup provides:
- Validation — Ensures public keys always have the correct format
- Security — Automatic memory zeroization of secrets
- Simplicity — Single function call instead of multiple steps
- Safety — Type-safe wrappers prevent misuse
Is this production-ready?
Yes! The library:
- Uses battle-tested dependencies (
age,zeroize) - Has comprehensive test coverage
- Follows Rust security best practices
- Is actively maintained
How do I save keys to disk?
use build_keypair;
use fs;
let keypair = build_keypair?;
// Save public key
write?;
// Save secret key (with proper permissions!)
let secret_content = format!;
write?;
Can I use this with async code?
Yes! Key generation is CPU-bound and very fast (~45µs), so you can call it directly:
spawn_blocking.await??;
Repository: https://github.com/neuxdotdev/age-setup
Issues: https://github.com/neuxdotdev/age-setup/issues
Crates.io: https://crates.io/crates/age-setup
Documentation: https://docs.rs/age-setup
Made with ️ by neuxdotdev