[](https://crates.io/crates/enc_file)
[](https://github.com/ArdentEmpiricist/enc_file)
[](https://github.com/ArdentEmpiricist/enc_file/actions/workflows/deploy.yml)
[](https://docs.rs/enc_file/)
[](https://github.com/ArdentEmpiricist/enc_file/blob/main/LICENSE)
[](https://crates.io/crates/enc_file)
# enc_file
<p align="center">
<img src="https://raw.githubusercontent.com/ArdentEmpiricist/enc_file/main/assets/logo.png" alt="enc_file Logo" width="200"/>
</p>
Password-based, authenticated file encryption with a small versioned header and Argon2id KDF. Ships as both a **library**, **CLI**, and **GUI application**.
> [!CAUTION]
> **Security note**: This project is **neither** audited **nor** reviewed. It protects data at rest but cannot defend a compromised host or advanced side channels. Use at your own risk. For important or sensitive information, use Veracrypt (or similar) instead.
## Features
- **Cross-platform GUI** with modern interface (optional)
- **Command-line interface** for automation and scripting
- **Rust library** for programmatic integration
- **File and byte array encryption/decryption**
- **Streaming encryption** for large files (constant memory usage)
- **Multiple AEAD algorithms**: XChaCha20-Poly1305, AES-256-GCM-SIV
- **Password-based key derivation** using Argon2id
- **Key map management** for named symmetric keys
- **Flexible hashing API** with support for BLAKE3, SHA2, SHA3, Blake2b, XXH3, and CRC32
- **ASCII armor** for encrypted data (Base64 encoding)
- **Argon2id** password KDF (per-file salt + stored parameters).
- AEAD: **XChaCha20-Poly1305** (default) or **AES-256-GCM-SIV**.
- Compact **binary header** (magic, version, alg, KDF kind/params, salt, nonce, length).
- Optional **ASCII armor** for transport.
- **Streaming mode** for large files (constant memory; configurable `chunk_size`).
- Use `secrecy` wrappers and zeroize buffers.
- Compute a file hash and print it as hex.
- Usable as **library**, **GUI** and **CLI**.
---
## Install
### GUI Application
To build and install the GUI version:
```bash
cargo install enc_file --features gui
# Then run: enc-file-gui
```
Or download pre-built binaries (including GUI) from the [Releases](https://github.com/ArdentEmpiricist/enc_file/releases) page.
Or clone and build locally:
```bash
git clone https://github.com/ArdentEmpiricist/enc_file.git
cd enc_file
cargo build --release --features gui
./target/release/enc-file-gui
```
### CLI Tool
```bash
cargo install enc_file
```
Or download pre-built binaries from the [Releases](https://github.com/ArdentEmpiricist/enc_file/releases) page (includes both CLI and GUI versions).
### Library
Add to your `Cargo.toml`:
```toml
[dependencies]
enc_file = "0.6"
```
## GUI Usage
The GUI provides an intuitive interface for file encryption, decryption, and hashing:
<p align="center">
<img src="https://raw.githubusercontent.com/ArdentEmpiricist/enc_file/refs/heads/main/assets/gui.png" alt="enc_file Logo" width="auto"/>
</p>
- **Modern Interface**: Clean, responsive design that works across platforms
- **Basic Mode**: Simple file selection, password entry, and one-click operations
- **Advanced Options**: Expandable panel with:
- Algorithm selection (XChaCha20-Poly1305, AES-256-GCM-SIV)
- Streaming mode for large files
- Custom chunk sizes
- ASCII armor output
- KDF parameter tuning (memory cost, iterations, parallelism)
- **Progress Indication**: Real-time progress bars and status messages
- **Results Display**: Copyable output with hash values and file paths
- **Password Strength**: Visual indicator for password security
### GUI Features
- **Encrypt Mode**: Select files, set passwords, choose algorithms
- **Decrypt Mode**: Decrypt files with automatic output path detection
- **Hash Mode**: Calculate file hashes with multiple algorithm support
- **Cross-Platform**: Runs on Windows, macOS, and Linux
- **File Browser Integration**: Native file picker dialogs
You can install **enc-file** in several ways:
### From crates.io (requires Rust toolchain)
```bash
cargo install enc-file
```
### From GitHub Releases (prebuilt binaries)
1. Visit the [Releases page](https://github.com/ArdentEmpiricist/enc_file/releases).
2. Download the binary for your platform.
3. Place it in a directory in your `PATH`.
### From source
```bash
# from source
cargo build --release
# binary
target/release/enc-file --help
```
Add to a project as a library:
```toml
# Cargo.toml
[dependencies]
enc_file = "0.5.16"
```
---
## CLI Usage
```
enc-file <SUBCOMMAND>
Subcommands:
enc Encrypt a file (use --stream for large files)
dec Decrypt a file
key Manage an encrypted key map
hash Compute a file hash and print it as hex
```
### Encrypt
```bash
# Simple: prompts for password and outputs secret.pdf.enc in same directory
enc-file enc --in secret.pdf
```
```bash
# Specify output filename, use AES-256-GCM-SIV and read password from file <PATH>
# Use shortcuts -i for --in and -o for --out
enc-file enc -i secret.pdf -o hidden.enc -a aes -p <PATH>
```
```bash
Options of interest:
-i, --in <file> Input file (required)
-o, --out <file> Output file
-a, --alg <algorithm> AEAD algorithm (xchacha default, aes)
--stream Enable streaming mode for large inputs
--chunk-size <bytes> Maximum frame length in streaming mode.
Default (0): adaptive sizing based on total file size:
• ≤ 1 MiB → 64 KiB
• 1 MiB–100 MiB → 1 MiB
• Files > 100 MiB → scales up (max 8 MiB)
Must be ≤ u32::MAX – 16 (32-bit length + 16 B tag).
-f, --force Overwrite output if file exists
--armor ASCII-armor output (streaming not supported)
-p, --password-file <path> Read password from file
```
### Decrypt
```bash
# Use --force (or -f) to overwrite existing file
enc-file dec --in secret.enc --out secret.pdf
```
### Hash
```bash
# Default blake3
enc-file hash README.md
# Specific algorithm (see below)
enc-file hash README.md --alg sha256
```
### Key map (optional)
If you use the library’s key map helpers, the CLI can provide small helpers to init/save/load. Check `enc-file key --help` for available subcommands.
---
## Library Usage
### Encrypt / Decrypt bytes
```rust
use enc_file::{encrypt_bytes, decrypt_bytes, EncryptOptions, AeadAlg};
use secrecy::SecretString;
let pw = SecretString::new("correct horse battery staple".into());
let opts = EncryptOptions {
alg: AeadAlg::XChaCha20Poly1305,
..Default::default()
};
let ct = encrypt_bytes(b"hello", pw.clone(), &opts)?;
let pt = decrypt_bytes(&ct, pw)?;
assert_eq!(pt, b"hello");
# Ok::<(), enc_file::EncFileError>(())
```
### Encrypt / Decrypt files
```rust
use enc_file::{encrypt_file, decrypt_file, EncryptOptions, AeadAlg};
use secrecy::SecretString;
use std::path::Path;
let pw = SecretString::new("pw".into());
let opts = EncryptOptions {
alg: AeadAlg::XChaCha20Poly1305, // or AeadAlg::Aes256GcmSiv
stream: false, // set true for large files
armor: false,
..Default::default()
};
let out = encrypt_file(Path::new("in.bin"), Some(Path::new("out.enc")), pw.clone(), opts)?;
let back = decrypt_file(&out, Some(Path::new("back.bin")), pw)?;
assert!(back.exists());
# Ok::<(), enc_file::EncFileError>(())
```
### Streaming encryption
```rust
use enc_file::{encrypt_file_streaming, EncryptOptions, AeadAlg};
use secrecy::SecretString;
use std::path::Path;
let pw = SecretString::new("pw".into());
let opts = EncryptOptions {
alg: AeadAlg::XChaCha20Poly1305,
stream: true,
chunk_size: 1024 * 1024, // 1 MiB chunks (example)
..Default::default()
};
let out = encrypt_file_streaming(Path::new("big.dat"), None, pw, opts)?;
# Ok::<(), enc_file::EncFileError>(())
```
> **Chunk size:**
> In streaming mode, `--chunk-size 0` (the default) enables an adaptive helper that picks an optimal frame size based on the total file length:
>
> - ≤ 1 MiB → 64 KiB
> - 1 MiB – 100 MiB → 1 MiB
> - Files larger than 100 MiB → scales up (max 8 MiB)
>
> You can override this by passing any non-zero byte count. The absolute maximum is `u32::MAX - 16` bytes (each frame encodes its length as a 32-bit ciphertext-byte count plus a 16-byte AEAD tag), and any larger value will be rejected.
### Hash helpers
### Supported Hash Algorithms
Both the CLI and library support multiple hashing algorithms for files and byte slices:
| **BLAKE3** | `blake3` | 32 bytes |
| **BLAKE2b-512** | `blake2b` | 64 bytes |
| **SHA-256** | `sha256` | 32 bytes |
| **SHA-512** | `sha512` | 64 bytes |
| **SHA3-256** | `sha3-256`, `sha3256`, `sha3_256` | 32 bytes |
| **SHA3-512** | `sha3-512`, `sha3512`, `sha3_512` | 64 bytes |
| **XXH3-64** | `xxh3-64`, `xxh364` | 8 bytes |
| **XXH3-128** | `xxh3-128`, `xxh3128` | 16 bytes |
| **CRC32** | `crc32` | 4 bytes |
> [!CAUTION]
> XXH3 and CRC32 are non-cryptographic! Use with care.
**CLI Example**:
```bash
# Compute SHA3-512 hash of a file
enc-file hash --file data.bin --alg sha3-512
# Use XXH3-64 (fast, non-cryptographic)
enc-file hash --file data.bin --alg xxh3-64
```
**Library Example**:
```rust
use enc_file::{hash_file, to_hex_lower, HashAlg};
let digest = hash_file(std::path::Path::new("data.bin"), HashAlg::Sha3_512)?;
println!("{}", to_hex_lower(&digest));
# Ok::<(), enc_file::EncFileError>(())
```
```rust
use enc_file::{hash_bytes, hash_file, to_hex_lower, HashAlg};
let digest = hash_bytes(b"abc", HashAlg::Sha256);
assert_eq!(
to_hex_lower(&digest),
"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
);
let file_digest = hash_file(std::path::Path::new("README.md"), HashAlg::Blake3)?;
println!("{}", to_hex_lower(&file_digest));
# Ok::<(), enc_file::EncFileError>(())
```
### Keyed BLAKE3 (MAC-style)
```rust
use enc_file::hash_bytes_keyed_blake3;
let key = [0u8; 32];
let tag = hash_bytes_keyed_blake3(b"message", &key);
assert_eq!(tag.len(), 32);
# Ok::<(), ()>(())
```
### Key map helpers
```rust
use enc_file::{KeyMap, load_keymap, save_keymap};
use secrecy::SecretString;
use std::path::Path;
let mut km = KeyMap::new();
km.insert("service".into(), "supersecret".into());
let pw = SecretString::new("pw".into());
let path = Path::new("keymap.enc");
save_keymap(&km, path, pw.clone())?;
let loaded = load_keymap(path, pw)?;
assert_eq!(loaded, km);
# Ok::<(), enc_file::EncFileError>(())
```
---
## Error handling
All fallible APIs return `Result<_, EncFileError>`. The error type is trait-based (`thiserror::Error`) and covers all expected failures without panics.
**Error variants:**
- `Io(std::io::Error)`: I/O failures (file read/write issues)
- `Crypto`: AEAD encryption/decryption failures (bad password, tampering)
- `UnsupportedVersion(u16)`: File format version not supported
- `UnsupportedAead(u8)`: AEAD algorithm ID not supported
- `UnsupportedKdf(u8)`: Password KDF algorithm ID not supported
- `Malformed`: Corrupt or invalid file structure
- `Invalid(&'static str)`: Invalid argument or operation (e.g. streaming with keymap)
- `Serde(serde_cbor::Error)`: Serialization errors (CBOR encoding/decoding)
All errors are returned as `Err(EncFileError)`; they never panic for expected failures.
See library and CLI tests for examples of error handling.
---
## KDF defaults and bounds
This library uses **Argon2id** for password-based key derivation with hardened defaults:
- **Time cost**: 3 iterations (minimum)
- **Memory cost**: 64 MiB (minimum)
- **Parallelism**: min(4, number of CPU cores)
These parameters are enforced at the library level. The CLI uses compliant defaults automatically.
## Streaming and armor
- **Streaming mode** provides constant memory usage for large files using chunked framing
- **ASCII armor is ignored in streaming mode** - only non-streaming payloads can be armored
- Maximum chunk size is `u32::MAX - 16` bytes due to 32-bit frame length + 16-byte AEAD tag
## Compatibility policy
This library maintains backward compatibility for reading encrypted files across versions (beginning from 0.5).
**Backward-compatible format extensions** (optional header fields) may be added between minor releases.
Existing files remain decryptable by newer versions.
---
## Tips
- Use *streaming* for large files to keep memory predictable.
- Consider `--armor` when moving ciphertexts through systems that mangle binaries.
- For CLI automation, prefer `--password-file` over interactive prompts.
---
## License
Licensed under either of
- [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.txt)
- [MIT license](LICENSE)
at your option.
Any contribution intentionally submitted for inclusion in this work shall be
dual licensed as above, without any additional terms or conditions.
---
**Note on names**
The library crate is named `enc_file` (snake_case), which is the name you use when importing it in Rust code:
```rust
use enc_file::{hash_file, HashAlg};
```
The compiled CLI binary is named `enc-file` (kebab-case), which is the name you use when invoking it from the shell:
```bash
enc-file hash --file test.txt
```
This naming separation is intentional and follows common conventions.
---
## Feedback & Issues
Feedback, bug reports, and pull requests are highly appreciated! Open an [Issue](https://github.com/ArdentEmpiricist/enc_file/issues) or [start a discussion](https://github.com/ArdentEmpiricist/enc_file/discussions).