Files
fcry/src/error.rs
T
ddidderr 2f16e735c3 feat: split crate into library and thin CLI binary
The crypto engine was only reachable through the fcry binary; embedding
it in another Rust project meant shelling out to the CLI. Restructure
the crate so the binary sits on top of a proper library API.

- Add src/lib.rs exposing encrypt/decrypt/decrypt_range/derive_key, the
  header and policy types, and the secret-handling primitives.
- Replace the positional-argument wrapper ladder
  (encrypt_with_output_options, decrypt_with_argon_cap, ...) with
  options structs: EncryptOptions, DecryptOptions, DecryptRangeOptions
  and HeaderReadOptions. OutSinkOptions becomes the public
  OutputOptions and no longer carries the input path; the input is now
  an explicit parameter to OutSink::open_with_options so the
  same-file-aliasing guard's inputs are visible at each call site.
- File parameters take Option<PathBuf>/&Path instead of AsRef<str>, so
  non-UTF-8 paths work.
- FcryError implements Display and std::error::Error so it composes
  with anyhow/thiserror-style error handling in downstream crates.
- Move read_key_file and normalize_passphrase from main.rs into
  secrets.rs so library users get the same strict 32-byte key-file
  parsing and NFC passphrase normalization. The world-readable
  key-file warning stays in the CLI wrapper (read_key_file_cli).
- Drop now-unneeded #[allow(dead_code)] markers; ReadInfoChunk::Normal
  loses its unused byte-count payload.
- Add rustfmt.toml (StdExternalCrate grouping, crate-granularity
  imports) and reformat imports accordingly.
- Add tests/library_api.rs covering a file round-trip and a range
  decrypt through the public API with a raw key.

User-visible change: CLI behavior is unchanged except error output,
which is now human-readable Display text ("Error: wrong key or
passphrase") instead of the Rust Debug representation.

Test plan: cargo clippy (default, --tests, --benches) is clean;
cargo +nightly fmt produces no diff; cargo test passes 43 tests
including the new library_api integration tests.
2026-06-12 22:49:23 +02:00

69 lines
1.7 KiB
Rust

// SPDX-License-Identifier: MIT-0
use std::{fmt, io};
use chacha20poly1305::aead;
#[derive(Debug)]
pub enum FcryError {
Io(io::Error),
Crypto(aead::Error),
Rng(getrandom::Error),
Format(String),
Kdf(String),
Passphrase(String),
WrongKey,
}
impl fmt::Display for FcryError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Io(e) => write!(f, "I/O error: {e}"),
Self::Crypto(_) => write!(f, "cryptographic authentication failed"),
Self::Rng(e) => write!(f, "randomness error: {e}"),
Self::Format(msg) => write!(f, "format error: {msg}"),
Self::Kdf(msg) => write!(f, "KDF error: {msg}"),
Self::Passphrase(msg) => write!(f, "passphrase error: {msg}"),
Self::WrongKey => write!(f, "wrong key or passphrase"),
}
}
}
impl std::error::Error for FcryError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::Io(e) => Some(e),
Self::Rng(e) => Some(e),
Self::Crypto(_)
| Self::Format(_)
| Self::Kdf(_)
| Self::Passphrase(_)
| Self::WrongKey => None,
}
}
}
impl From<io::Error> for FcryError {
fn from(e: io::Error) -> Self {
FcryError::Io(e)
}
}
impl From<aead::Error> for FcryError {
fn from(e: aead::Error) -> Self {
FcryError::Crypto(e)
}
}
impl From<getrandom::Error> for FcryError {
fn from(e: getrandom::Error) -> Self {
FcryError::Rng(e)
}
}
impl From<argon2::Error> for FcryError {
fn from(e: argon2::Error) -> Self {
FcryError::Kdf(e.to_string())
}
}