updated README
This commit is contained in:
@@ -1,12 +1,172 @@
|
|||||||
# fcry - [f]ile[cry]pt
|
# fcry - filecrypt
|
||||||
A file en-/decryption tool for easy use.
|
|
||||||
|
|
||||||
Currently `fcry` uses `ChaCha20Poly1305` ([RFC 8439](https://datatracker.ietf.org/doc/html/rfc8439)) as [AEAD](https://en.wikipedia.org/wiki/Authenticated_encryption) cipher provided by the [chacha20poly1305](https://docs.rs/chacha20poly1305/latest/chacha20poly1305/) crate.
|
`fcry` encrypts and decrypts files with an authenticated chunked format. New
|
||||||
|
files use XChaCha20-Poly1305 in a STREAM-style construction: a 19-byte random
|
||||||
|
nonce prefix, a 32-bit chunk counter, and a last-chunk bit form each 24-byte
|
||||||
|
XChaCha nonce. Every chunk authenticates the full file header as AEAD
|
||||||
|
associated data.
|
||||||
|
|
||||||
## Status
|
The tool is intended for local file encryption, scripted backups, and
|
||||||
Currently `fcry` is __not thoroughly tested__ and in __early stages of development__.
|
streaming-friendly decrypts. It is not a general archive format, does not hide
|
||||||
There is a chance, that something is broken as of now.
|
file size, and does not protect plaintext after another process has received
|
||||||
Encryption __seems__ to work, but due to a possible lack of understanding of some underlying methods
|
it.
|
||||||
(or misinterpretation) it could theoretically be not effective at all.
|
|
||||||
|
|
||||||
See [TODO.md](/ddidderr/fcry/src/branch/main/TODO.md) for further information.
|
## Usage
|
||||||
|
|
||||||
|
Encrypt with an interactive passphrase:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
fcry -i plain.bin -o plain.bin.fcry --passphrase
|
||||||
|
```
|
||||||
|
|
||||||
|
Decrypt with the same passphrase:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
fcry -d -i plain.bin.fcry -o plain.bin --passphrase
|
||||||
|
```
|
||||||
|
|
||||||
|
Use a raw 32-byte key file instead of a passphrase:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
fcry -i plain.bin -o plain.bin.fcry --key-file key.bin
|
||||||
|
fcry -d -i plain.bin.fcry -o plain.bin --key-file key.bin
|
||||||
|
```
|
||||||
|
|
||||||
|
For non-interactive passphrase use:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
FCRY_PASSWORD='correct horse battery staple' \
|
||||||
|
fcry -i plain.bin -o plain.bin.fcry --passphrase-env FCRY_PASSWORD
|
||||||
|
```
|
||||||
|
|
||||||
|
`--passphrase-env` is useful for automation, but the environment variable can
|
||||||
|
remain visible to the current process environment and platform tooling. Prefer
|
||||||
|
interactive entry or a protected key file when possible.
|
||||||
|
|
||||||
|
## Safety Properties
|
||||||
|
|
||||||
|
- File outputs are written to private, randomly named temporary files and are
|
||||||
|
renamed into place only after encryption or decryption succeeds. Existing
|
||||||
|
outputs require `--force`, except for the self-replacement case that is
|
||||||
|
handled through the temporary file.
|
||||||
|
- New passphrase encryptions use Argon2id by default with 1024 MiB of memory,
|
||||||
|
2 passes, and 4 lanes. Passphrases must be non-empty and at least 12 UTF-8
|
||||||
|
bytes unless `--allow-weak-kdf` is explicitly supplied for tests or legacy
|
||||||
|
interop.
|
||||||
|
- Decryption enforces a memory ceiling for Argon2id headers. The default cap is
|
||||||
|
the lower of 4096 MiB, the architecture limit, and available Linux memory
|
||||||
|
when that can be detected. Override it with `--max-argon-memory-mib` only for
|
||||||
|
files you trust.
|
||||||
|
- Chunk size is bounded to `1..=64 MiB`. Worker threads are capped at 256, and
|
||||||
|
the pipeline bounds in-flight chunk memory.
|
||||||
|
- v3 files carry a key commitment derived from the stretched key and committed
|
||||||
|
header fields. This gives a fast, clear wrong-key failure before chunk
|
||||||
|
processing and prevents stripping or downgrading the commitment without
|
||||||
|
authentication failure.
|
||||||
|
- On Unix, `fcry` makes a best-effort call to disable core dumps for the process
|
||||||
|
before handling secrets.
|
||||||
|
|
||||||
|
## Format
|
||||||
|
|
||||||
|
The current on-disk format version is v3.
|
||||||
|
|
||||||
|
```text
|
||||||
|
magic "fcry" 4 bytes
|
||||||
|
version u8 1
|
||||||
|
alg_id u8 1 (1 = XChaCha20-Poly1305)
|
||||||
|
flags u8 1
|
||||||
|
reserved u8 1 (must be 0)
|
||||||
|
chunk_size u32 LE 4
|
||||||
|
kdf_id u8 1 (0 = raw key, 1 = Argon2id)
|
||||||
|
kdf_params variable
|
||||||
|
nonce_prefix [u8; 19]
|
||||||
|
plaintext_length u64 LE only when flags bit 0 is set
|
||||||
|
key_commitment [u8; 32] only when flags bit 1 is set
|
||||||
|
ciphertext chunks each plaintext chunk plus a 16-byte Poly1305 tag
|
||||||
|
```
|
||||||
|
|
||||||
|
The encoded header is AEAD associated data for every chunk. Changing the chunk
|
||||||
|
size, KDF parameters, nonce prefix, committed plaintext length, key commitment,
|
||||||
|
or other header bytes causes authentication failure.
|
||||||
|
|
||||||
|
Version history:
|
||||||
|
|
||||||
|
- v1: no flags and no committed plaintext length.
|
||||||
|
- v2: adds the length-committed flag and optional `plaintext_length`.
|
||||||
|
- v3: requires the key-commitment flag and stores the 32-byte key commitment.
|
||||||
|
|
||||||
|
Regular file encryption commits `plaintext_length` in the header. Stdin
|
||||||
|
encryption cannot know the final length up front, so stdin-produced files do
|
||||||
|
not support random-access decrypt.
|
||||||
|
|
||||||
|
## Streaming And Ranges
|
||||||
|
|
||||||
|
Normal decrypt-to-stdout emits each plaintext chunk after that chunk has
|
||||||
|
authenticated. This means a truncated ciphertext can produce an authentic
|
||||||
|
prefix on stdout before the final truncation error is reported. That is
|
||||||
|
inherent to chunked streaming AE when bytes are released immediately.
|
||||||
|
|
||||||
|
Use `--buffer-verify` when decrypting to stdout if downstream consumers must
|
||||||
|
not see any plaintext until the whole file has authenticated:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
fcry -d -i plain.bin.fcry --passphrase --buffer-verify > plain.bin
|
||||||
|
```
|
||||||
|
|
||||||
|
`--buffer-verify` writes plaintext to a private temporary file first, verifies
|
||||||
|
the complete ciphertext, and copies to stdout only after success. File outputs
|
||||||
|
already get atomic temporary-file behavior, so `--buffer-verify` is only valid
|
||||||
|
for decrypt-to-stdout.
|
||||||
|
|
||||||
|
Random-access decrypt requires `--decrypt`, `--input-file`, `--offset`, and
|
||||||
|
`--length`, and the input must have a length-committed header:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
fcry -d -i plain.bin.fcry --passphrase --offset 1048576 --length 4096 > slice.bin
|
||||||
|
```
|
||||||
|
|
||||||
|
A successful range decrypt authenticates the requested chunks and header. It
|
||||||
|
does not prove that the rest of the file is present or untampered. Use a full
|
||||||
|
decrypt when you need whole-file integrity. `--length 0` is rejected because it
|
||||||
|
would authenticate no chunks.
|
||||||
|
|
||||||
|
## Threat Model
|
||||||
|
|
||||||
|
`fcry` aims to provide confidentiality and integrity for file contents against
|
||||||
|
an attacker who can read, copy, truncate, replace, or modify ciphertext files
|
||||||
|
after encryption. With passphrase mode, offline guessing is still possible; the
|
||||||
|
Argon2id parameters make each guess expensive but cannot make a weak passphrase
|
||||||
|
safe.
|
||||||
|
|
||||||
|
The format authenticates all header fields that affect decryption, including
|
||||||
|
KDF parameters, chunk size, nonce prefix, committed plaintext length, and key
|
||||||
|
commitment. Unknown header flags and unsupported algorithms are rejected.
|
||||||
|
|
||||||
|
The following are explicit non-goals:
|
||||||
|
|
||||||
|
- Hiding plaintext length or access patterns. `plaintext_length` is cleartext
|
||||||
|
for regular-file encryptions, and ciphertext length already reveals an
|
||||||
|
approximate plaintext size. There is no padding scheme.
|
||||||
|
- Preventing plaintext exposure after successful decrypt. Plaintext written to
|
||||||
|
stdout, files, pipes, shell history, terminals, swap, backups, or downstream
|
||||||
|
tools is outside `fcry`'s control.
|
||||||
|
- Protecting plaintext chunk buffers from every local memory-forensics route.
|
||||||
|
Keys and passphrases use protected/zeroizing storage where practical, and
|
||||||
|
chunk buffers are zeroized on drop, but decrypted plaintext necessarily exists
|
||||||
|
in ordinary process memory while being processed.
|
||||||
|
- Disabling Windows Error Reporting or minidumps. Unlike Unix core dumps, those
|
||||||
|
are controlled by per-machine Windows policy; `fcry` records this as an
|
||||||
|
operator/deployment responsibility rather than changing host-wide policy.
|
||||||
|
- Recovering from loss of the passphrase or raw key file. There is no escrow or
|
||||||
|
backdoor.
|
||||||
|
|
||||||
|
## Operational Notes
|
||||||
|
|
||||||
|
- Keep backups of important plaintext until you have verified the encrypted
|
||||||
|
file and your recovery path.
|
||||||
|
- Store raw key files with restrictive permissions. On Unix, `fcry` warns when
|
||||||
|
a key file is group/world accessible.
|
||||||
|
- Use `--allow-weak-kdf` only for tests or compatibility with old intentionally
|
||||||
|
weak files.
|
||||||
|
- Use `--temp-dir` when the default temporary-file location is not acceptable
|
||||||
|
for decrypt-to-stdout buffering or output staging.
|
||||||
|
|||||||
Reference in New Issue
Block a user