ferrocrypt 0.3.0

Recipient-oriented file and directory encryption: passphrase (Argon2id) and X25519 public-key recipients, XChaCha20-Poly1305 STREAM payloads, HKDF-SHA3-256 / HMAC-SHA3-256 key derivation and authentication.
Documentation
[package]
name = "ferrocrypt"
version = "0.3.0"
edition = "2021"
rust-version = "1.87"

description = "Recipient-oriented file and directory encryption: passphrase (Argon2id) and X25519 public-key recipients, XChaCha20-Poly1305 STREAM payloads, HKDF-SHA3-256 / HMAC-SHA3-256 key derivation and authentication."
authors = ["Alexander Alexandrov"]
license = "GPL-3.0-only"
readme = "../README.md"
repository = "https://github.com/alexylon/ferrocrypt"
homepage = "https://www.ferrocrypt.app"
documentation = "https://docs.rs/ferrocrypt"
keywords = ["cryptography", "encryption", "chacha20poly1305", "argon2", "X25519"]
categories = ["cryptography"]
publish = true
# Test-only fixtures; the private.key among them is not a real secret.
# The frozen conformance corpus is published at the release tag rather than in
# the crate (`FORMAT.md` §12.3), and it is append-only, so shipping it would
# grow every download for material no library user needs.
exclude = ["tests/fixtures/", "testvectors/wire/"]

[features]
# Gives the fuzz targets in ferrocrypt-lib/fuzz access to internal
# parsers. Features prefixed `unstable-` are outside the crate's
# public API guarantee; their items may change in any release.
unstable-fuzzing = []

[dependencies]
x25519-dalek = { version = "2", features = ["static_secrets"] }
zeroize = "1"
thiserror = "2"
chacha20poly1305 = { version = "0.10", features = ["std", "stream"] }
argon2 = { version = "0.5", features = ["std", "zeroize"] }
# hmac 0.13 and hkdf 0.13 require sha3 0.11, so the three move together,
# and ferrocrypt-test-support's sha3 moves with them.
# The `zeroize` features wipe internal hash state on drop; hkdf has no
# such feature but uses hmac inside, so it is covered too.
sha3 = { version = "0.11", features = ["zeroize"] }
hmac = { version = "0.13", features = ["zeroize"] }
hkdf = "0.13"
# Keeps the crate building on Rust 1.87: 0.4.2 needs 1.85, but 0.5 needs 1.95.
constant_time_eq = ">=0.4.2, <0.5"
bech32 = "0.11"
tempfile = "3"
# Filesystem layer of the hardened extractor (archive/platform.rs):
# every open is anchored to an already-open directory handle and
# refuses symlinks, so extraction cannot escape the output folder.
# cap-fs-ext adds the no-follow opens that cap-std itself lacks.
cap-std = "4"
cap-fs-ext = "4"
# Detects two archive paths that are the same visible name written in
# two Unicode spellings. macOS treats such names as one name, so the
# pair is rejected before it can enter an archive (FORMAT.md §9.7).
unicode-normalization = "0.1"

[target.'cfg(unix)'.dependencies]
libc = "0.2"
# Used on Linux and macOS for the handle-relative operations the standard
# library does not expose — the no-replace rename, the interruptible
# flush — and on every Unix except Linux for the permission restore that
# must open nothing. cap-std also depends on rustix on every non-Windows
# target, so both must accept the same version.
rustix = { version = "1", features = ["fs"] }

[dev-dependencies]
ferrocrypt-test-support = { path = "../ferrocrypt-test-support" }
ctor = "0.9"
stats_alloc = "0.1.10"

# `process` is for the archive/encode.rs test that lowers the open-file limit.
[target.'cfg(any(target_os = "linux", target_os = "macos"))'.dev-dependencies]
rustix = { version = "1", features = ["process"] }