Expand description
Argon2id recipient/identity plugin for the age encryption format.
This crate provides password-based encryption for age files using Argon2id key derivation instead of scrypt. It also provides cached variants that skip the KDF entirely for session-based workflows.
§Quick start
Full KDF encrypt → decrypt roundtrip:
use age_plugin_argon2::{Argon2idRecipient, Argon2idIdentity, Argon2Params};
use age::{Recipient, Identity};
use age_core::format::FileKey;
use secrecy::ExposeSecret;
let passphrase = b"hunter2";
let params = Argon2Params::new(256, 1, 1).unwrap(); // use stronger params in production
// Encrypt
let recipient = Argon2idRecipient::new(passphrase, params);
let file_key = FileKey::new(Box::new([0u8; 16]));
let (stanzas, _labels) = recipient.wrap_file_key(&file_key).unwrap();
// Decrypt
let identity = Argon2idIdentity::new(passphrase);
let recovered = identity.unwrap_stanza(&stanzas[0]).unwrap().unwrap();
assert_eq!(recovered.expose_secret(), file_key.expose_secret());§Cached / session mode
After an initial KDF decryption, captured material can be reused to avoid running Argon2id on every subsequent encrypt/decrypt:
use age_plugin_argon2::{Argon2idRecipient, Argon2idIdentity, CachedRecipient, CachedIdentity, Argon2Params};
use age::{Recipient, Identity};
use age_core::format::FileKey;
use secrecy::ExposeSecret;
let passphrase = b"hunter2";
let params = Argon2Params::new(256, 1, 1).unwrap();
// Initial full-KDF encrypt + decrypt to capture session material
let (stanzas, _) = Argon2idRecipient::new(passphrase, params)
.wrap_file_key(&FileKey::new(Box::new([0u8; 16])))
.unwrap();
let identity = Argon2idIdentity::new(passphrase);
identity.unwrap_stanza(&stanzas[0]).unwrap().unwrap();
let material = identity.captured_material().unwrap();
// Session re-encrypt without running Argon2id
let session_key = FileKey::new(Box::new(material.file_key));
let (session_stanzas, _) = CachedRecipient::new(&material)
.wrap_file_key(&session_key)
.unwrap();
// Session decrypt — also skips KDF
let recovered = CachedIdentity::new(&material)
.unwrap_stanza(&session_stanzas[0])
.unwrap()
.unwrap();
assert_eq!(recovered.expose_secret(), &[0u8; 16]);§Security model
Two operational modes with different security/performance trade-offs:
§Full KDF (Argon2idRecipient / Argon2idIdentity)
Used at session boundaries (init, unlock). Every encrypt/decrypt runs the full Argon2id KDF to derive a wrapping key from the passphrase + random salt. The wrapping key protects the age FileKey via ChaCha20-Poly1305 AEAD.
- Encrypt: random salt → Argon2id → wrapping key → AEAD-wrap FileKey
- Decrypt: parse salt from stanza → Argon2id → wrapping key → AEAD-unwrap FileKey
- Key capture: on successful decrypt,
Argon2idIdentitycaptures the FileKey + wrapping key + salt asCachedMaterialfor session caching
§Cached / zero-KDF (CachedRecipient / CachedIdentity)
Used during an active session after the initial unlock. The passphrase is never stored — only opaque key material (64 bytes) lives in the OS keychain.
CachedRecipient(writes): reuses the captured wrapping key + salt to AEAD-wrap the FileKey without running Argon2id. Produces stanzas indistinguishable from full-KDF output.CachedIdentity(reads): returns the cached FileKey directly. Stanza body verification is intentionally skipped because the age STREAM layer provides per-chunk Poly1305 authentication — a wrong FileKey will fail at payload decryption, not silently produce garbage.
§Stanza format
-> thesis.co/argon2 <base64-salt> <m_cost> <t_cost> <p_cost>
<AEAD-wrapped FileKey>The namespaced tag (thesis.co/argon2) avoids collisions with any future
upstream age scrypt/argon2 recipient type.
Re-exports§
pub use cached::CachedIdentity;pub use cached::CachedMaterial;pub use cached::CachedRecipient;pub use encrypt::encrypt_with_file_key;pub use encrypt::EncryptWithFileKeyError;pub use identity::Argon2idIdentity;pub use params::Argon2Params;pub use params::InvalidParams;pub use recipient::Argon2idRecipient;
Modules§
- cached
- Cached / zero-KDF recipient and identity for session use.
- encrypt
- Low-level age-format encryption with a caller-supplied FileKey. Custom age-format writer that accepts a known FileKey.
- identity
- Full-KDF identity for passphrase-based decryption.
- params
- Validated Argon2id parameters.
- recipient
- Full-KDF recipient for passphrase-based encryption.