@thoisoithree/fcrypt-darwin-arm64
v0.3.1
Published
Prebuilt fcrypt binary for macOS arm64
Readme
fcrypt
fcrypt is a cross-platform Rust CLI for local file encryption, decryption,
key generation, and post-quantum asymmetric encryption.
The crate name is filecrypt; the installed binary is fcrypt.
fcrypt is designed for large files. It processes data as authenticated
chunks, writes outputs through temporary files, and finalizes results only after
the operation succeeds.
Release 0.3.x compatibility notice
Version 0.3.0 introduced the opaque .bin container format, retained by the
0.3.x releases. It does not provide backward compatibility for pre-0.3.0
encrypted files.
To read old files created by fcrypt 0.2.0 or earlier, use fcrypt version
0.2.0.
Highlights
- Opaque password-based encrypted files with no cleartext magic bytes, version, algorithm identifiers, or recipient identifiers.
- Password slots use a fixed opaque v1 Argon2id profile: 128 MiB, time cost 3, parallelism 1.
- Post-quantum asymmetric encryption with ML-KEM-1024 + HQC-256 recipient slots.
- AES-256-GCM streaming payload encryption with
u64chunk indexes. - Detached ML-DSA-87 signatures for opaque ciphertext files.
- Explicit identity creation with
identity create <name>for recipient and signing key pairs. The legacyasym encryptworkflow retains its historical automatic key generation behavior. - Random password generation and Diceware-style passphrase generation from the embedded EFF large wordlist.
- Atomic output workflow: plaintext, ciphertext, signature, and key files are written through temporary files first.
- npm packages with prebuilt binaries for Linux, macOS, and Windows on x64 and arm64.
Security model
Password encryption
Password mode uses the opaque container format:
password -> fixed Argon2id profile -> password slot -> manifest key
manifest key -> encrypted manifest -> file secret
file secret -> HKDF-SHA3-512 -> AES-256-GCM payload chunksThe password is entered through a hidden terminal prompt. The password is not stored in the encrypted file and is not logged.
Asymmetric encryption
Asymmetric mode uses recipient keys:
ML-KEM-1024 shared secret ┐
├─ HKDF-SHA3-512 ── slot key ── manifest key
HQC-256 shared secret ────┘
manifest key -> encrypted manifest -> file secret
file secret -> HKDF-SHA3-512 -> AES-256-GCM payload chunksML-KEM-1024 and HQC-256 provide two independent post-quantum KEM layers for recipient access.
Optional detached signatures use ML-DSA-87:
opaque ciphertext transcript -> ML-DSA-87 signature -> <ciphertext>.sigA recipient key and a signing key are different keys:
*_recipient_default.pubis shared with people who should encrypt files for the recipient.*_recipient_default.secdecrypts matching opaque files and must remain secret.*_signer_mldsa87.pubis shared with people who should verify signatures.*_signer_mldsa87.seccreates signatures and must remain secret.
Never share .sec files.
Install
npm
npm install -g @thoisoithree/fcrypt
fcrypt --helpThe npm package installs a small launcher and a prebuilt platform binary for the current OS/CPU.
Published platform packages:
@thoisoithree/fcrypt-linux-x64@thoisoithree/fcrypt-linux-arm64@thoisoithree/fcrypt-darwin-x64@thoisoithree/fcrypt-darwin-arm64@thoisoithree/fcrypt-win32-x64@thoisoithree/fcrypt-win32-arm64
GitHub release binaries
GitHub Releases provide raw binary files and .sha256 checksum files for:
- Linux x64:
fcrypt-linux-x64 - Linux arm64:
fcrypt-linux-arm64 - macOS Intel:
fcrypt-darwin-x64 - macOS Apple Silicon:
fcrypt-darwin-arm64 - Windows x64:
fcrypt-win32-x64.exe - Windows arm64:
fcrypt-win32-arm64.exe
Build from source
cargo build --release --lockedAsymmetric PQC mode is enabled by default through the pqc feature and uses
Open Quantum Safe liboqs through Rust oqs bindings. Building with PQC
support can require:
- Rust stable
- C compiler
- CMake
- platform build tools
To build only the password-based mode:
cargo build --release --locked --no-default-featuresWhen built without the pqc feature, fcrypt asym ... / fcrypt assym ...
commands return a clear error and password mode remains available.
Help
Short command-local help:
fcrypt -h
fcrypt encrypt -h
fcrypt decrypt -h
fcrypt identity -h
fcrypt sign -h
fcrypt verify -hFull help for every command, option, alias, and example:
fcrypt help-allThe compatibility forms -ha and --help-all are also accepted. They are
handled before command parsing, except after --, so a file literally named
-ha remains a valid input path.
fcrypt --help-allCommand overview
# Recommended commands
fcrypt encrypt <INPUT> [-o <OUTPUT>]
fcrypt decrypt <INPUT.bin> [-o <OUTPUT>]
fcrypt sign <INPUT.bin> --key <SIGNER.SEC>
fcrypt verify <INPUT.bin> --key <SIGNER.PUB>
fcrypt identity create <NAME>
fcrypt identity list
fcrypt identity inspect <KEY>
fcrypt password generate --length <N>
fcrypt phrase generate --words <N>
# Compatibility commands
fcrypt asym ...
fcrypt assym ...
fcrypt keygen ...encrypt and encode are aliases. decrypt and decode are aliases. The
legacy asym, assym, and keygen command groups remain supported.
Password-based usage
Encrypt a file:
fcrypt encrypt report.pdfEquivalent alias:
fcrypt encode report.pdfThe output is:
report.pdf.binDecrypt:
fcrypt decrypt report.pdf.binEquivalent alias:
fcrypt decode report.pdf.binForce overwrite of an existing output file:
fcrypt decrypt report.pdf.bin --forceChoose a specific output path:
fcrypt encrypt report.pdf --output archive.bin
fcrypt decrypt archive.bin --output report-restored.pdfFor automation, read a password from a protected file. A single trailing LF or CRLF is removed; other whitespace remains part of the password:
fcrypt encrypt report.pdf --password-file ./fcrypt-password.txt --json
fcrypt decrypt report.pdf.bin --password-file ./fcrypt-password.txt --quiet--json emits one machine-readable result to stdout. --quiet suppresses
normal success messages and progress, while --no-progress keeps final output
but hides progress indicators. Passwords must never be supplied as command-line
arguments.
Asymmetric PQC opaque usage
Recommended recipient-key workflow
fcrypt identity create alice
fcrypt encrypt report.pdf --recipient ./alice_recipient_default.pubThe unified command never creates a recipient key silently. Use
--new-identity <NAME> when intentional one-off identity creation is desired.
Back up the generated recipient .sec file: without it, encrypted data cannot
be recovered.
Sign and verify ciphertexts without decrypting:
fcrypt sign report.pdf.bin --key ./alice_signer_mldsa87.sec
fcrypt verify report.pdf.bin --key ./alice_signer_mldsa87.pub
fcrypt decrypt report.pdf.bin \
--identity ./alice_recipient_default.sec \
--verify ./alice_signer_mldsa87.pubGenerate named recipient and signing keys
Generate four key files in the current directory:
fcrypt keygen pair aliceOutput files:
alice_recipient_default.pub
alice_recipient_default.sec
alice_signer_mldsa87.pub
alice_signer_mldsa87.secKeys are non-expiring by default. To create keys with a lifetime in days:
fcrypt keygen pair alice 365Encrypt for an existing recipient
fcrypt asym encrypt report.pdf -r ./alice_recipient_default.pubLong option:
fcrypt asym encrypt report.pdf --recipient-public ./alice_recipient_default.pubWhen -r / --recipient-public is provided, no new recipient keypair is
generated.
Choose a key directory
By default, keys are saved next to the input file in <file_stem>_keys:
report.pdf -> report_keys/
docs/report.pdf -> docs/report_keys/
archive.tar.gz -> archive.tar_keys/Override it with -k / --keys-dir:
fcrypt asym encrypt report.pdf -k ./keysWhen --keys-dir is provided, fcrypt uses that directory directly and does
not create a nested report_keys/ directory.
Decrypt
fcrypt asym decrypt report.pdf.bin -i ./report_keys/a13f2c9b_recipient_default.secEquivalent alias:
fcrypt asym decode report.pdf.bin -i ./report_keys/a13f2c9b_recipient_default.secIf -i / --identity is omitted, fcrypt tries available recipient secret
keys in the default or provided keys directory:
fcrypt asym decrypt report.pdf.bin
fcrypt asym decrypt report.pdf.bin -k ./report_keysOpaque ciphertexts do not reveal which recipient key should be tried.
Auto-discovery is therefore bounded to 32 matching recipient secret key files;
use -i to select a specific key when needed.
Encrypt and sign
Generate a signing key automatically and create a detached signature:
fcrypt asym encrypt report.pdf -sGenerated files:
report.pdf.bin
report.pdf.bin.sig
report_keys/
<label8>_recipient_default.pub
<label8>_recipient_default.sec
<label8>_signer_mldsa87.pub
<label8>_signer_mldsa87.secSign with an existing signing key:
fcrypt asym encrypt report.pdf -S ./alice_signer_mldsa87.sec-S / --sign-key automatically enables signing, so this is equivalent to
-s -S ./alice_signer_mldsa87.sec.
Sign an existing opaque file
Create a detached signature:
fcrypt asym sign report.pdf.binOutput:
report.pdf.bin.sigUse an existing signing key:
fcrypt asym sign report.pdf.bin -S ./alice_signer_mldsa87.secEmbedded signatures are not supported for opaque files.
Verify signatures while decrypting
Verify with a signer public key:
fcrypt asym decrypt report.pdf.bin \
-i ./report_keys/a13f2c9b_recipient_default.sec \
-v ./alice_signer_mldsa87.pubRequire a valid signature:
fcrypt asym decrypt report.pdf.bin \
-i ./report_keys/a13f2c9b_recipient_default.sec \
-v ./alice_signer_mldsa87.pub \
-RWhen --verify <signer.pub> is used, a valid detached signature is required
before decryption. The legacy -R / --require-signature option remains
accepted for compatibility and still requires a verification key.
Options
encrypt / encode
<INPUT>, -i, --input <FILE> Path to the input file.
-f, --force Overwrite the destination file without asking.decrypt / decode
<INPUT>, -i, --input <FILE> Path to the input file.
-f, --force Overwrite the destination file without asking.asym encrypt / asym encode
-o, --output <FILE> Destination .bin file. Defaults to <INPUT>.bin.
-r, --recipient-public <FILE> Recipient public key bundle.
-k, --keys-dir <DIR> Directory for generated or discovered keys.
-s, --sign Create a detached ML-DSA-87 signature.
-S, --sign-key <FILE> Signing secret key. Implies --sign.
-f, --force Overwrite output and signature files without asking.asym decrypt / asym decode
-o, --output <FILE> Destination plaintext file. Defaults to <INPUT.bin without .bin>.
-i, --identity <FILE> Recipient secret key bundle.
-k, --keys-dir <DIR> Directory for recipient secret key auto-discovery.
-v, --verify <FILE> Signing public key for signature verification.
-R, --require-signature Require a valid signature before decrypting.
-f, --force Overwrite the destination file without asking.asym sign
-o, --output <FILE> Detached signature output. Defaults to <INPUT>.sig.
-S, --sign-key <FILE> Signing secret key bundle. Generated if omitted.
-k, --keys-dir <DIR> Directory for generated signing keys.
-e, --embed Unsupported for opaque files.
-f, --force Overwrite the signature file without asking.Key generation
Random password
fcrypt password generate --length 32password generate writes a random password with N characters to stdout followed by
a newline. N must be between 1 and 4096.
The password generator uses the operating system CSPRNG and this portable alphabet:
A-Z a-z 0-9 ! # $ % & ( ) * + , - . / : ; < = > ? @ [ ] ^ _ { | } ~Random passphrase
Generate a phrase from the embedded EFF large wordlist:
fcrypt phrase generate --words 7Use a custom separator:
fcrypt phrase generate --words 7 --separator .
fcrypt phrase generate --words 7 --separator _
fcrypt phrase generate --words 7 --separator " "keygen phrase uses the embedded EFF large wordlist with 7,776 words. Word
selection is cryptographically random and uniform. The default separator is
-.
Named asymmetric key pairs
fcrypt identity create alice
fcrypt identity create alice --lifetime-days 365identity create writes one recipient keypair and one signing keypair. The optional
lifetime is in days. The key filename prefix accepts ASCII letters, digits,
., _, and -, and must not start with ..
Opaque file format
Both password and asymmetric encryption use the same opaque .bin container.
The outer file has no magic bytes, cleartext format version, cleartext
algorithm identifiers, cleartext KDF parameters, or cleartext recipient key id.
Fixed outer layout:
32 bytes file nonce
8 * 16384 recipient slots
4112 bytes encrypted manifest
rest encrypted payload chunksThe encrypted manifest contains the internal format version, plaintext length, chunk size, chunk count, tag length, and random payload file secret.
Password slots use opaque v1 Argon2id:
memory: 131072 KiB (128 MiB)
time cost: 3
parallelism: 1
output: 32 bytesPayload chunks use AES-256-GCM. Chunk nonces are:
4-byte per-file nonce base || 8-byte big-endian chunk indexSee docs/OPAQUE_FORMAT.md for implementation-level
details.
Output naming
Encryption appends .bin to the full filename:
report.pdf -> report.pdf.binDecryption removes .bin when present:
report.pdf.bin -> report.pdfLegacy .enc suffixes are accepted only for output-path mapping:
old-file.enc -> old-fileThey do not imply legacy file format support in 0.3.x.
If the input has neither .bin nor .enc, decryption appends .dec:
archive.dat -> archive.dat.decSource files are never modified in place.
Release artifacts and package repositories
The release workflow builds raw binaries and SHA-256 checksum files for Linux,
macOS, and Windows. Tagging a release with vX.Y.Z triggers GitHub Actions
release automation.
APT and RPM repositories are published by the package repository workflow when
repository signing secrets are configured. See
docs/PACKAGE_REPOSITORIES.md for setup and
install commands.
Release process details are documented in RELEASE.md.
Development
Run tests:
cargo test --lockedRun clippy:
cargo clippy --all-targets --all-features -- -D warningsBuild release:
cargo build --release --lockedBuild without asymmetric PQC mode:
cargo build --release --locked --no-default-featuresTest coverage
The test suite covers:
- password small-file, empty-file, and chunk-boundary roundtrips;
- wrong password, corrupted ciphertext, and truncated file failures;
- opaque prelude tamper detection;
- fixed password KDF profile behavior;
- asymmetric opaque roundtrips;
- explicit recipient public key encryption and secret key decryption;
- bounded recipient key auto-discovery;
- detached ML-DSA-87 signatures;
- standalone signature verification and unified password/PQC CLI workflows;
- required signature failures;
- named
keygen pairgeneration with and without lifetime; - output naming rules;
- overwrite behavior;
- random password and EFF wordlist passphrase generation;
help-alland compatibility-ha/--help-alloutput.
Security notes
- Keep
.secfiles private. - Share only
.pubfiles. - A recipient
.seckey can decrypt matching opaque files. - A signer
.seckey can create signatures as that signer. - Use
--verify <signer.pub>when authenticity is mandatory during decryption. - Expired recipient secret keys remain usable for archival decryption, and expired signing public keys remain usable for historical verification. Expired recipient public keys and signing secret keys cannot be used for new work.
- Keep backups of recipient secret keys; losing the matching recipient
.seckey makes recovery impossible. - Password-based files cannot be recovered without the original password.
fcrypt0.3.xcannot read pre-0.3.0 encrypted files. Use version0.2.0for those files.
License
MIT. See LICENSE.
