Expand description
§ferrocrypt
High-level file encryption for files and directories.
FerroCrypt writes .fcr files using one recipient-oriented v1 container:
one random per-file key, one streamed authenticated payload, and one or more
typed recipient entries that independently wrap the same file key. The public
API exposes this through Encryptor and Decryptor rather than through
low-level cryptographic building blocks.
§Design goals
- Recipient-oriented encryption: passphrases and public keys are native
recipient schemes over the same
.fcrcontainer. - Path-based file workflows: archiving, streaming encryption, staging, and output naming are handled by the library.
- Typed routing:
Decryptor::openinspects the recipient list and returns a passphrase or private-key decryptor variant. - Typed diagnostics: operations return
CryptoErrorvalues with structured format, KDF, recipient, authentication, and I/O failures.
§Quick start (passphrase recipient)
use ferrocrypt::{Decryptor, Encryptor, CryptoError, secrecy::SecretString};
let passphrase = SecretString::from("correct horse battery staple".to_string());
// Encrypt
let encrypted = Encryptor::with_passphrase(passphrase.clone())
.write("./secrets", "./out", |ev| eprintln!("{ev}"))?;
println!("Encrypted to {}", encrypted.output_path.display());
// Decrypt
let restored = match Decryptor::open(&encrypted.output_path)? {
Decryptor::Passphrase(d) => d.decrypt(passphrase, "./restored", |ev| eprintln!("{ev}"))?,
Decryptor::PrivateKey(_) => unreachable!("we just encrypted with a passphrase"),
_ => unreachable!("Decryptor is non_exhaustive; v1 has only Passphrase + PrivateKey"),
};
println!("Decrypted to {}", restored.output_path.display());§Quick start (public-key recipients)
use ferrocrypt::{
Decryptor, Encryptor, generate_key_pair, PublicKey, PrivateKey,
CryptoError, secrecy::SecretString,
};
// 1) Generate X25519 keypair
let passphrase = SecretString::from("my-key-pass".to_string());
let keys = generate_key_pair("./keys", passphrase.clone(), |ev| eprintln!("{ev}"))?;
println!("Fingerprint: {}", keys.fingerprint);
// 2) Encrypt with the recipient's public key (no passphrase required)
let encrypted = Encryptor::with_public_key(PublicKey::from_key_file(&keys.public_key_path))
.write("./payload", "./out", |ev| eprintln!("{ev}"))?;
// 3) Decrypt with the recipient's private key + passphrase
let restored = match Decryptor::open(&encrypted.output_path)? {
Decryptor::PrivateKey(d) => d.decrypt(
PrivateKey::from_key_file(&keys.private_key_path),
passphrase,
"./restored",
|ev| eprintln!("{ev}"),
)?,
Decryptor::Passphrase(_) => unreachable!("we just encrypted to a public key"),
_ => unreachable!("Decryptor is non_exhaustive; v1 has only Passphrase + PrivateKey"),
};
println!("Decrypted to {}", restored.output_path.display());§Choosing a recipient path
- Passphrase recipient: use
Encryptor::with_passphrasewhen the same passphrase should encrypt and decrypt the file. The resulting.fcrcontains exactly one nativeargon2idrecipient. - Public-key recipient: use
Encryptor::with_public_keyorEncryptor::with_public_keyswhen the sender should encrypt to one or more public recipient keys. Decryption requires a matchingPrivateKeyfile and that key file’s passphrase. This does not authenticate the sender.
§Format compatibility
The current on-disk format is FerroCrypt v1 for .fcr, public.key, and
private.key. The compatibility guarantee starts with the first stable
0.3.0 release. During the 0.3.0 pre-release series (-alpha.N,
-beta.N, -rc.N), the format is not yet frozen: files written by a
pre-release or by main carry no cross-version guarantee and may fail to
decrypt under a later pre-release.
Once the format is frozen, files written by any release that produces format v1 will decrypt under any later release that supports format v1. If a future release introduces format v2, format v1 reading will be maintained for compatibility with older files.
Older pre-v1 files and key pairs use a different format family and, for historical hybrid encryption, a different key-agreement stack. To migrate older data, decrypt it with the release that created it, then re-encrypt it with the current release.
§API stability
The on-disk format is versioned independently from the crate; see
Format compatibility above for its stability guarantee.
The public Rust API (Encryptor, Decryptor, PublicKey,
PrivateKey, the error types) is pre-1.0; it may change in minor releases
(0.x → 0.y), while patch releases (0.x.y → 0.x.z) preserve it. See the
repository CHANGELOG.md
for release notes.
§Security notes
- All cryptographic operations depend on a secure OS RNG; ensure the target platform provides one.
- Sender authentication is out of scope; public-key encryption identifies who can decrypt, not who encrypted.
- Ciphertext integrity is enforced; modification or wrong keys yield
CryptoErrorresults rather than corrupted plaintext. - Passphrase and key-pair writing reject Argon2id memory below a fixed
19 MiB floor with
CryptoError::KdfBelowWriteFloor, so a.fcrorprivate.keycannot be sealed with a weak passphrase work factor by accident. The floor applies only when writing; decryption accepts any structurally valid file. - FerroCrypt authenticates each file as written, but it does not detect
replay or rollback to an older valid
.fcr; use external versioning or a freshness check if that matters. - FerroCrypt encrypts file contents and, for directory inputs, internal
names, tree structure, and per-file sizes. It does not hide the total
ciphertext length (an approximate plaintext-size signal), recipient count,
or that the file is a FerroCrypt
.fcrcontainer. - This crate is not third-party audited and is not advertised as compliance-certified.
§Error handling
Every fallible operation returns Result<T, CryptoError>. See
CryptoError for variant meanings and remediation hints.
§License
Licensed under GPL-3.0-only. See the LICENSE file in the repository.
Re-exports§
pub use secrecy;
Structs§
- Archive
Limits - Resource caps for FCA archive encoding and extraction.
- Authenticated
Recipient Mode - Recipient mode established by a successful authenticated decrypt.
- Decrypt
Outcome - Successful outcome of
PassphraseDecryptor::decryptorPrivateKeyDecryptor::decrypt. - Encrypt
Outcome - Successful outcome of an
Encryptor::writecall. - Encryptor
- Builder-style entry point for encryption.
- Header
Read Limits - Local resource caps applied while reading an encrypted-file header.
- KdfLimit
- Local policy limit for Argon2id work accepted during decryption.
- KdfParams
- KDF parameters stored in file headers and key files.
- KeyGen
Outcome - Successful outcome of
generate_key_pairorKeyPairGenerator::write. - KeyPair
Generator - Builder for X25519 key-pair generation.
- Passphrase
Decryptor - Decryptor for passphrase-sealed
.fcrfiles. Returned fromDecryptor::openwhen the file’s recipient list classifies asUnauthenticatedRecipientMode::Passphrase. - Private
Key - Private key for public-key-recipient decryption.
- Private
KeyDecryptor - Decryptor for public-key-sealed
.fcrfiles. Returned fromDecryptor::openwhen the file’s recipient list classifies asUnauthenticatedRecipientMode::PublicKey. - Public
Key - Public recipient key for FerroCrypt public-key encryption.
Enums§
- Authenticated
Recipient Mode Kind - Public, forward-compatible discriminant for
AuthenticatedRecipientMode. The variant carries no authentication authority on its own — only anAuthenticatedRecipientModevalue does, and that wrapper is unforgeable outside the crate. - Crypto
Error - Errors that can occur during key generation, encryption, or decryption.
- Decryptor
- Type-safe entry point for decryption.
- Format
Defect - Structural defects detected while parsing a FerroCrypt encrypted file
or key file. Carried inside
CryptoError::InvalidFormatso format failures can be pattern-matched without substring comparisons and without heap-allocatedStrings. - Incomplete
Output Policy - Policy for the
.incompleteworking tree when decrypt fails. - Invalid
KdfParams - Which KDF parameter from an untrusted header failed its structural bound check. Carries the raw value so callers can decide whether to re-try with looser limits.
- Mixing
Policy - Public diagnostic category for a recipient mixing rule, surfaced
through
CryptoError::IncompatibleRecipients. - Progress
Event - Structured progress signal emitted during encrypt, decrypt, and key generation.
- Unauthenticated
Recipient Mode - Result of a cheap structural probe of an
.fcrfile’s recipient list. - Unsupported
Version - File-format or key-file version rejection. Carries the raw version byte so callers can inspect it without parsing a formatted string.
Constants§
- ARGO
N2_ SALT_ SIZE - Argon2id salt size in bytes. Stored alongside
KdfParamsin any header that consumes a passphrase (argon2id recipient body,private.keycleartext header).KdfParams::hash_passphrasetakes its salt as&[u8; ARGON2_SALT_SIZE]. - ENCRYPTED_
EXTENSION - Default file extension for encrypted FerroCrypt payload files.
- FCR_
FILE_ VERSION - Version byte for the
.fcrouter encrypted file (FORMAT.md§3.1). - KDF_
PARAMS_ SIZE - Serialized size of
KdfParamsin bytes (3 ×u32big-endian). - MAGIC
- 4-byte ASCII magic identifying every FerroCrypt v1 artefact.
- PRIVATE_
KEY_ FILENAME - Default filename for the private key file (binary, wrapped).
- PRIVATE_
KEY_ V1_ VERSION - Canonical v1
private.keywire-version byte. Mirrors the suite constant fromKeypairSuite::V1(crate-internal) so bumping the keypair suite flows through this constant automatically. - PRIVATE_
KEY_ VERSION - Wire-version byte the current writer emits in
private.keyheaders. Derived fromWRITER_KEYPAIR_SUITE(crate-internal); not an independent support list. - PUBLIC_
KEY_ FILENAME - Default filename for the public key file (text form).
- PUBLIC_
KEY_ V1_ VERSION - Canonical v1 wire-version byte for
public.keyrecipient payloads. Mirrors the suite constant fromKeypairSuite::V1(crate-internal) so bumping the keypair suite flows through this constant automatically. - PUBLIC_
KEY_ VERSION - Wire-version byte the current writer emits at offset 0 of every
public.keyrecipient payload. Derived fromWRITER_KEYPAIR_SUITE(crate-internal); mirrorscrate::key::private::PRIVATE_KEY_VERSIONso a future suite bump flows through both writers in lockstep. - VERSION
- The version of this crate, captured from
Cargo.tomlat compile time.
Functions§
- decode_
recipient_ string - Decodes a Bech32 recipient string (
fcr1…) into raw X25519 public-key material. - default_
encrypted_ filename - Returns the default encrypted filename for a given input path.
- generate_
key_ pair - Generates and stores an X25519 key pair for public-key (recipient) encryption.
- probe_
recipient_ mode - Cheap structural probe of an
.fcrfile’s recipient list. Not a security claim. - probe_
recipient_ mode_ with_ limits - Same as
probe_recipient_modebut uses the suppliedHeaderReadLimitsfor the structural header read instead of the conservative defaults. - validate_
private_ key_ file - Validates that a file is a well-formed FerroCrypt
private.keyfile. - validate_
public_ key_ file - Validates that a file is a well-formed FerroCrypt
public.keytext file.