enc_file 0.6.1

Password-based file encryption tool with a versioned header, AEAD, Argon2id KDF, and streaming mode. Library + CLI + GUI.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
[![Crates.io](https://img.shields.io/crates/v/enc_file?label=Crates.io)](https://crates.io/crates/enc_file)
[![Clippy](https://img.shields.io/github/actions/workflow/status/ArdentEmpiricist/enc_file/rust-clippy.yml?label=Rust%20Clippy)](https://github.com/ArdentEmpiricist/enc_file)
[![Deploy](https://github.com/ArdentEmpiricist/enc_file/actions/workflows/deploy.yml/badge.svg)](https://github.com/ArdentEmpiricist/enc_file/actions/workflows/deploy.yml)
[![Documentation](https://docs.rs/enc_file/badge.svg)](https://docs.rs/enc_file/)
[![Crates.io](https://img.shields.io/crates/l/enc_file?label=License)](https://github.com/ArdentEmpiricist/enc_file/blob/main/LICENSE)
[![Crates.io](https://img.shields.io/crates/d/enc_file?color=darkblue&label=Downloads)](https://crates.io/crates/enc_file)
[![Rust Edition](https://img.shields.io/badge/rust-2024-orange)](https://blog.rust-lang.org/2024/10/17/Rust-1.82.0.html)

# 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 a **library**, **CLI**, and **GUI application**.

> [!CAUTION]
> **Security note**: This project is **neither** audited **nor** reviewed. It protects data at rest but cannot defend against a compromised host or advanced side channels. Use at your own risk. For highly sensitive information, use audited tools like [VeraCrypt]https://www.veracrypt.fr/ or [age]https://github.com/FiloSottile/age.

## Table of Contents

- [Features]#features
- [Installation]#installation
  - [GUI Application]#gui-application
  - [CLI Tool]#cli-tool
  - [Library]#library
- [GUI Usage]#gui-usage
- [CLI Usage]#cli-usage
  - [Encrypt]#encrypt
  - [Decrypt]#decrypt
  - [Hash]#hash
  - [Key Map]#key-map-optional
- [Library Usage]#library-usage
  - [Encrypt/Decrypt Bytes]#encrypt--decrypt-bytes
  - [Encrypt/Decrypt Files]#encrypt--decrypt-files
  - [Streaming Encryption]#streaming-encryption
  - [Hash Helpers]#hash-helpers
  - [Keyed BLAKE3 (MAC-style)]#keyed-blake3-mac-style
  - [Key Map Helpers]#key-map-helpers
- [Hash Algorithms]#hash-algorithms
- [Error Handling]#error-handling
- [Technical Details]#technical-details
  - [KDF Defaults and Bounds]#kdf-defaults-and-bounds
  - [Streaming and Armor]#streaming-and-armor
  - [Compatibility Policy]#compatibility-policy
- [Security Best Practices]#security-best-practices
- [Tips]#tips
- [License]#license
- [Contributing]#contributing

---

## Features


- **Cross-platform GUI** with modern, intuitive interface (optional feature).
- **Command-line interface** for automation and scripting.
- **Rust library** for programmatic integration.
- **File and byte array encryption/decryption**.
- **Multiple AEAD algorithms**: XChaCha20-Poly1305 (default), AES-256-GCM-SIV.
- **Streaming mode** for large files with constant memory usage and configurable `chunk_size`.
- **Password-based key derivation** using Argon2id with hardened defaults.
- **Key map management** for named symmetric keys.
- **Flexible hashing API** supporting BLAKE3, SHA2, SHA3, Blake2b, XXH3, and CRC32.
- **ASCII armor** for encrypted data (Base64 encoding).
- **Compact binary header** (magic, version, algorithm IDs, KDF parameters, salt, nonce, length).
- **Secure by default**: Uses `secrecy` wrappers and zeroizes sensitive buffers.

---

## Installation

### GUI Application

**Option 1: Install from crates.io**

```bash
cargo install enc_file --features gui
# Then run: enc-file-gui
```

**Option 2: Download pre-built binaries**

Download from the [Releases](https://github.com/ArdentEmpiricist/enc_file/releases) page (includes both CLI and GUI versions for Windows, macOS, and Linux).

**Option 3: Build from source**

```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

**Option 1: Install from crates.io**

```bash
cargo install enc_file
```

**Option 2: Download pre-built binaries**

Download from the [Releases](https://github.com/ArdentEmpiricist/enc_file/releases) page.

### 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 GUI Screenshot" width="auto"/>
</p>

### GUI Features

- **Modern Interface**: Clean, responsive design that works across all 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 Indicator**: Visual feedback for password security
- **File Browser Integration**: Native file picker dialogs

### Available Operations

- **Encrypt Mode**: Select files, set passwords, choose algorithms, and configure advanced options
- **Decrypt Mode**: Decrypt files with automatic output path detection or custom output paths
- **Hash Mode**: Calculate file hashes with support for multiple algorithms
- **Cross-Platform**: Runs on Windows, macOS, and Linux

---

## 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

**Simple usage** (prompts for password, outputs to same directory with `.enc` extension):

```bash
enc-file enc --in secret.pdf
```

**Advanced usage** with custom output, algorithm selection, and password file:

```bash
# Use AES-256-GCM-SIV and read password from file
enc-file enc -i secret.pdf -o hidden.enc -a aes -p /path/to/password.txt
```

**Streaming mode** for large files:

```bash
# Enable streaming with custom chunk size
enc-file enc -i large_video.mp4 --stream --chunk-size 2097152
```

**Available options**:
  **Available options**:

```
  -i, --in <file>            Input file (required)
  -o, --out <file>           Output file (default: input + ".enc")
  -a, --alg <algorithm>      AEAD algorithm (xchacha [default], aes)
      --stream               Enable streaming mode for large files
      --chunk-size <bytes>   Chunk size in streaming mode
                             Default (0): adaptive sizing based on file size:
                               • ≤ 1 MiB         → 64 KiB  
                               • 1 MiB–100 MiB   → 1 MiB  
                               • > 100 MiB       → scales up to 8 MiB max
                             Must be ≤ 4,294,967,279 (u32::MAX - 16)
  -f, --force                Overwrite output if it exists
      --armor                ASCII-armor output (Base64; streaming not supported)
  -p, --password-file <path> Read password from file (trailing newline trimmed)
```

### Decrypt

**Simple usage**:

```bash
enc-file dec --in secret.enc
```

**With custom output**:

```bash
# Use --force (or -f) to overwrite existing files
enc-file dec --in secret.enc --out secret.pdf --force
```

**Available options**:

```
  -i, --in <file>            Input file (required)
  -o, --out <file>           Output file (default: auto-detected)
  -p, --password-file <path> Read password from file
  -f, --force                Overwrite output if it exists
```

### Hash

**Default** (BLAKE3):

```bash
enc-file hash README.md
```

**Specific algorithm**:

```bash
enc-file hash README.md --alg sha256
```

See [Hash Algorithms](#hash-algorithms) section for all supported algorithms.

### Key Map (optional)
```

### 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

### Hash Algorithms

Both the CLI and library support multiple hashing algorithms for files and byte slices:

| Algorithm            | CLI `--alg` value(s)                                      | Output length | Cryptographic |
|----------------------|-----------------------------------------------------------|---------------|---------------|
| **BLAKE3**           | `blake3` (default)                                        | 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!** They provide fast checksums for data integrity but offer no security guarantees. Do not use them for security-critical applications.

**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 implements `thiserror::Error` and covers all expected failures without panicking.

**Error variants**:

- `Io(std::io::Error)`: I/O failures (file read/write issues, permissions)
- `Crypto`: AEAD encryption/decryption failures (wrong password, data tampering, authentication failure)
- `UnsupportedVersion(u16)`: File format version not supported by this version
- `UnsupportedAead(u8)`: AEAD algorithm ID not recognized
- `UnsupportedKdf(u8)`: Password KDF algorithm ID not recognized
- `Malformed`: Corrupt or invalid file structure (truncated, missing headers)
- `Invalid(&'static str)`: Invalid argument or operation (e.g., streaming with armor, invalid chunk size)
- `Cbor(ciborium::de::Error)`: CBOR deserialization errors
- `CborSer(ciborium::ser::Error)`: CBOR serialization errors

All errors are returned as `Err(EncFileError)` and never panic for expected failures.

---

## Technical Details

### KDF defaults and bounds

### KDF defaults and bounds

This library uses **Argon2id** for password-based key derivation with hardened, security-focused defaults:

- **Time cost (iterations)**: 3 passes (minimum recommended for 2024+)
- **Memory cost**: 64 MiB (65,536 KiB) minimum
- **Parallelism**: min(4, number of CPU cores) to balance performance and DoS prevention

These parameters are enforced at the library level and provide strong protection against brute-force attacks while maintaining reasonable performance. The CLI uses compliant defaults automatically.

**Why these values?**
- Higher memory cost makes GPU/ASIC attacks more expensive
- Multiple iterations increase computational cost
- Limited parallelism prevents resource exhaustion attacks

### Streaming and armor

- **Streaming mode** provides constant memory usage for large files using chunked framing
- **ASCII armor is not compatible with streaming mode** - only non-streaming payloads can be armored
- Maximum chunk size is **4,294,967,279 bytes** (u32::MAX - 16) due to 32-bit frame length + 16-byte AEAD tag
- Adaptive chunk sizing automatically selects optimal chunk sizes based on file size when `--chunk-size 0` is used

### Compatibility policy

This library maintains **backward compatibility** for reading encrypted files across versions (starting from v0.5).

- Files encrypted with older versions can be decrypted by newer versions
- Backward-compatible format extensions (optional header fields) may be added between minor releases
- Breaking changes to the file format will result in a major version bump
- The `version` field in the header enables graceful handling of format changes

---

## Security Best Practices

While `enc_file` uses strong cryptography, security depends on proper usage:

### Password Guidelines

- **Use strong, unique passwords**: Minimum 16+ characters with mixed case, numbers, and symbols
- **Use a password manager** to generate and store passwords securely
- **Never reuse passwords** across different files or services
- **Avoid dictionary words** or predictable patterns

### Operational Security

- **Secure password entry**: Use `--password-file` carefully; ensure file permissions are restrictive (`chmod 600`)
- **Clean up**: Delete password files after use if no longer needed
- **Verify decryption**: Always test that encrypted files can be decrypted before deleting originals
- **Secure deletion**: Use `shred` or similar tools to securely delete plaintext files after encryption

### Threat Model Limitations

This tool is designed for **data-at-rest protection**. It does NOT protect against:

- **Compromised host**: Malware, keyloggers, or rootkits can steal passwords and keys
-**Side-channel attacks**: Power analysis, timing attacks (use hardware security modules for high-security needs)
-**Memory forensics**: Plaintext may temporarily reside in RAM during operation

### When to Use Audited Alternatives

For highly sensitive data or compliance requirements, consider audited tools:
- **[VeraCrypt]https://www.veracrypt.fr/**: Full disk encryption, audited
- **[age]https://github.com/FiloSottile/age**: Modern file encryption, reviewed
- **[GPG]https://gnupg.org/**: Industry standard, long-term support

---

## Tips

- **Use streaming mode** (`--stream`) for files larger than available RAM to keep memory usage constant
- **Enable ASCII armor** (`--armor`) when transferring files through systems that might corrupt binary data
- **For CLI automation**, prefer `--password-file` over interactive prompts
- **Test decryption** immediately after encryption to verify the file and password are correct
- **Backup important files** before encryption, and verify successful decryption before deleting originals
- **Use specific algorithms** when needed - XChaCha20-Poly1305 (default) for general use, AES-256-GCM-SIV for AES-NI hardware acceleration
- **Adjust KDF parameters** only if you understand the security implications
- **Check file integrity** using the hash command before and after transfer

---

## 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.

### Contribution

Any contribution intentionally submitted for inclusion in this work shall be
dual licensed as above, without any additional terms or conditions.

---

## Contributing

Contributions are welcome! Please follow these guidelines:

1. **Open an issue first** for major changes to discuss your proposal
2. **Follow Rust conventions**: Run `cargo fmt` and `cargo clippy` before submitting
3. **Add tests** for new functionality
4. **Update documentation** including README and doc comments
5. **Keep commits atomic** with clear, descriptive messages

See the [Issues](https://github.com/ArdentEmpiricist/enc_file/issues) page for known bugs and feature requests, or [start a discussion](https://github.com/ArdentEmpiricist/enc_file/discussions) for questions and ideas.

---

## Project Structure

- `src/lib.rs` - Public library API
- `src/main.rs` - CLI application
- `src/gui_main.rs` - GUI application (requires `gui` feature)
- `src/crypto.rs` - Core encryption/decryption logic
- `src/format.rs` - File format definitions
- `src/hash.rs` - Hashing implementations
- `src/kdf.rs` - Key derivation functions
- `src/streaming.rs` - Streaming mode implementation
- `tests/` - Integration tests

---

**Note on Binary 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 Rust conventions.

---

## Feedback & Support

- **Bug reports**: Open an [Issue]https://github.com/ArdentEmpiricist/enc_file/issues
- **Feature requests**: Open an [Issue]https://github.com/ArdentEmpiricist/enc_file/issues or [Discussion]https://github.com/ArdentEmpiricist/enc_file/discussions
- **Questions**: Start a [Discussion]https://github.com/ArdentEmpiricist/enc_file/discussions
- **Security concerns**: Please report security vulnerabilities privately by email to the repository owner

---