anubis-age

Crates.ioanubis-age
lib.rsanubis-age
version1.4.0
created_at2025-10-09 16:43:05.229966+00
updated_at2025-10-10 07:30:04.779133+00
descriptionPost-quantum secure encryption library with hybrid X25519+ML-KEM-1024 mode (internal dependency for anubis-rage)
homepage
repositoryhttps://github.com/AnubisQuantumCipher/anubis-rage
max_upload_size
id1875892
size1,962,660
(AnubisQuantumCipher)

documentation

README

age Rust library (Anubis Rage Edition)

Post-quantum secure file encryption library with hybrid X25519+ML-KEM-1024 support


age is a simple, modern, and secure file encryption library. This is the Anubis Rage edition, which extends the original age library with defense-in-depth post-quantum cryptography through hybrid mode combining X25519 and ML-KEM-1024.

Features

  • 🛡️ Hybrid Mode (RECOMMENDED): X25519 + ML-KEM-1024 defense-in-depth
  • 🔐 Quantum-Resistant: ML-KEM-1024 (NIST FIPS 203) for post-quantum security
  • 🎯 Classical Algorithms: X25519, scrypt, and SSH key support remain available
  • 🚀 Simple API: Small explicit keys, no config options, UNIX-style composability
  • ⚡ High Performance: Efficient implementations via liboqs and Rust crypto ecosystem
  • 🔒 NIST Level-5: Highest standardized post-quantum security level (256-bit equivalent)

What's New in Anubis Rage v2.0

This crate provides a set of Rust APIs that can be used to build tools based on the age format, with defense-in-depth post-quantum cryptography:

Hybrid Mode (NEW in v2.0)

  • Defense-in-Depth: Combines X25519 ECDH with ML-KEM-1024 KEM
  • Dual-Algorithm Security: Attacker must break BOTH algorithms
  • Industry Standard: Same approach as Signal Protocol, TLS 1.3
  • NIST Compliant: Follows NIST SP 800-56C Rev. 2 for hybrid KDF

Pure Post-Quantum Mode

  • ML-KEM-1024 Recipients: Encrypt to quantum-resistant public keys
  • ML-KEM-1024 Identities: Decrypt with quantum-resistant private keys
  • NIST Standardized: Implements FIPS 203 approved post-quantum KEM

Classical Mode

  • Backward Compatible: Still supports X25519, scrypt, and SSH keys
  • Battle-Tested: Proven security against classical attacks

The primary consumer of these APIs is the anubis-rage CLI tool, which provides straightforward quantum-resistant encryption and decryption of files or streams.

Format Specification

The age format specification is at age-encryption.org/v1.

Anubis Rage extends this with two post-quantum recipient stanza formats:

Hybrid Mode (RECOMMENDED)

-> hybrid [base64-x25519-epk] [base64-mlkem-ciphertext]
[base64-encoded-wrapped-file-key]

Pure ML-KEM-1024

-> mlkem1024 [base64-encoded-ciphertext]
[base64-encoded-wrapped-file-key]

The age format was designed by @Benjojo and @FiloSottile.

The reference interoperable Go implementation is available at filippo.io/age.

Installation

Add this line to your Cargo.toml:

anubis-age = "2.0"

For post-quantum features, ensure you have liboqs installed:

macOS:

brew install liboqs

Ubuntu/Debian:

sudo apt-get install cmake ninja-build
git clone https://github.com/open-quantum-safe/liboqs.git
cd liboqs && mkdir build && cd build
cmake -GNinja -DCMAKE_INSTALL_PREFIX=/usr/local ..
ninja && sudo ninja install

Usage

Hybrid Mode (RECOMMENDED - Defense-in-Depth)

use age::pqc::hybrid::{Identity, Recipient};
use age::{Encryptor, Decryptor};
use std::io::{Read, Write};

// Generate a new hybrid identity (X25519 + ML-KEM-1024)
let identity = Identity::generate();
let recipient = identity.to_public();

// Encrypt
let encryptor = Encryptor::with_recipients(vec![Box::new(recipient)])
    .expect("we provided a recipient");

let mut encrypted = vec![];
let mut writer = encryptor.wrap_output(&mut encrypted)?;
writer.write_all(b"Secret message with defense-in-depth security")?;
writer.finish()?;

// Decrypt
let decryptor = match Decryptor::new(&encrypted[..])? {
    Decryptor::Recipients(d) => d,
    _ => unreachable!(),
};

let mut decrypted = vec![];
let mut reader = decryptor.decrypt(std::iter::once(&identity as &dyn age::Identity))?;
reader.read_to_end(&mut decrypted)?;

assert_eq!(decrypted, b"Secret message with defense-in-depth security");

Pure ML-KEM-1024 (Post-Quantum Only)

use age::pqc::mlkem::{Identity, Recipient};

// Generate a new ML-KEM-1024 identity (quantum-resistant only)
let identity = Identity::generate();
let recipient = identity.to_public();

// Use same Encryptor/Decryptor API as above

Using X25519 (Classical)

use age::x25519;

let identity = x25519::Identity::generate();
let recipient = identity.to_public();

// Use same Encryptor/Decryptor API as above

Using Passphrase Encryption

use age::scrypt;

let identity = scrypt::Identity::new("correct horse battery staple");

// Encrypt
let encryptor = Encryptor::with_user_passphrase(
    secrecy::SecretString::new("correct horse battery staple".to_string())
);

// Decrypt using scrypt::Identity

API Documentation

See the documentation for complete API details and examples.

Feature Flags

  • pqc-mlkem - Enables ML-KEM-1024 and hybrid mode support (enabled by default)
  • armor - Enables the age::armor module for ASCII-armored age files
  • async - Enables asynchronous APIs for encryption and decryption
  • cli-common - Common helper functions for building age CLI tools
  • ssh - Enables the age::ssh module for reusing SSH key files
  • web-sys - WebAssembly support for passphrase work factor calculation
  • unstable - In-development functionality (no stability guarantees)

Security Considerations

Hybrid Mode (RECOMMENDED)

Hybrid mode provides defense-in-depth by requiring an attacker to break BOTH:

  • X25519 ECDH: ~128-bit classical security (discrete log problem)
  • ML-KEM-1024: ~256-bit quantum security (Module-LWE problem)

Key Properties:

  • No Single Point of Failure: If either algorithm is broken, the other still protects data
  • Future-Proof: Protected against both classical and quantum attacks
  • Industry Standard: Same approach used in Signal Protocol, TLS 1.3, SSH
  • NIST Compliant: Follows NIST SP 800-56C Rev. 2 hybrid key derivation

Pure Post-Quantum Security

ML-KEM-1024 provides:

  • IND-CCA2 security: Indistinguishability under adaptive chosen-ciphertext attack
  • NIST Level-5: Equivalent to AES-256 classical security
  • Quantum resistance: Secure against Shor's and Grover's algorithms
  • Standardized: NIST FIPS 203 compliant

Classical Security

X25519, scrypt, and SSH support remain available for:

  • Backward compatibility with existing age files
  • Integration with existing SSH infrastructure
  • Scenarios where post-quantum security is not required

Recommendations

Use Case Recommended Mode Rationale
Long-term data protection Hybrid Defense-in-depth, no single point of failure
High-security scenarios Hybrid Industry best practice
General file encryption Hybrid Future-proof with minimal overhead
Legacy compatibility X25519 Interoperability with original age
Passphrase-based scrypt Simple, password-based encryption

Comparison with Original rage

Feature Anubis Rage v2.0 Original rage
Hybrid Mode ✅ X25519 + ML-KEM-1024 ❌ No
Post-Quantum Security ✅ ML-KEM-1024 ❌ No
Defense-in-Depth ✅ Dual-algorithm ❌ Single algorithm
NIST Standardized PQC ✅ FIPS 203
X25519 Support ✅ Yes ✅ Yes
SSH Key Support ✅ Yes ✅ Yes
Passphrase Encryption ✅ Yes ✅ Yes
File Compatibility ✅ Full (with age v1) ✅ Standard age
Quantum Resistant ✅ With hybrid/ML-KEM ❌ No

Examples

Multiple Recipients (Defense-in-Depth)

use age::pqc::hybrid;

let hybrid_identity = hybrid::Identity::generate();

// Encrypt to hybrid recipient (recommended)
let recipients: Vec<Box<dyn age::Recipient>> = vec![
    Box::new(hybrid_identity.to_public()),
];

let encryptor = Encryptor::with_recipients(recipients)
    .expect("we provided recipients");

Streaming Encryption

use age::Encryptor;
use age::pqc::hybrid;
use std::io::Write;

let recipient = hybrid::Identity::generate().to_public();
let encryptor = Encryptor::with_recipients(vec![Box::new(recipient)])?;

let output = std::fs::File::create("encrypted.age")?;
let mut writer = encryptor.wrap_output(output)?;

// Stream data in chunks
for chunk in data_chunks {
    writer.write_all(chunk)?;
}

writer.finish()?;

ASCII Armoring

use age::armor::ArmoredWriter;
use age::pqc::hybrid;

let recipient = hybrid::Identity::generate().to_public();
let encryptor = Encryptor::with_recipients(vec![Box::new(recipient)])?;

let output = Vec::new();
let armored = ArmoredWriter::wrap_output(output, age::armor::Format::AsciiArmor)?;
let mut writer = encryptor.wrap_output(armored)?;

writer.write_all(b"Secret data")?;
let armored_output = writer.finish()?.into_inner()?;

// armored_output contains ASCII-armored ciphertext

Migration from v1.x

Files encrypted with v1.x (pure ML-KEM-1024) can still be decrypted by v2.0:

// Old v1.x files using pure ML-KEM-1024
let old_mlkem_identity = age::pqc::mlkem::Identity::from_string("mlkem1024-sk-...");

// Works fine in v2.0
let decryptor = Decryptor::new(old_file_data)?;
let reader = decryptor.decrypt(std::iter::once(&old_mlkem_identity))?;

For new encryptions, we recommend migrating to hybrid mode:

// New v2.0 hybrid mode (recommended)
let new_hybrid_identity = age::pqc::hybrid::Identity::generate();
let recipient = new_hybrid_identity.to_public();

// Encrypt with defense-in-depth
let encryptor = Encryptor::with_recipients(vec![Box::new(recipient)])?;

Library Development

Building

# Build the library
cargo build --release

# Run tests
cargo test

# Build with all features
cargo build --all-features

Testing

# Run all tests
cargo test

# Test hybrid mode specifically
cargo test hybrid

# Test with sanitizers (requires nightly)
RUSTFLAGS="-Z sanitizer=address" cargo +nightly test

Contributing

See CONTRIBUTING.md for guidelines on:

  • Code style and conventions
  • Adding new features
  • Localization support
  • Testing requirements

License

Licensed under either of:

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Acknowledgments

  • NIST - For post-quantum cryptography standardization (FIPS 203)
  • Open Quantum Safe - For the liboqs ML-KEM-1024 implementation
  • Signal Foundation - For pioneering hybrid post-quantum cryptography
  • Filippo Valsorda & Ben Cox - For designing the age format
  • Original rage contributors - For the excellent foundation
  • Rust crypto community - For high-quality cryptography crates

Further Reading


Anubis Rage v2.0 - Defense-in-depth protection for the quantum era.

Commit count: 0

cargo fmt