Qsafe 4.0: durable public-key workflow, pipes, metadata, cross-platform#1
Open
SP1R4 wants to merge 4 commits into
Open
Qsafe 4.0: durable public-key workflow, pipes, metadata, cross-platform#1SP1R4 wants to merge 4 commits into
SP1R4 wants to merge 4 commits into
Conversation
Breaking change — the on-disk format is bumped to "QSAFE003" and is incompatible with 2.x files (different KEM and key-file layout). Security - Switch KEM from round-3 Kyber1024 to ML-KEM-1024, so the FIPS 203 claim is accurate (OQS_KEM_alg_ml_kem_1024, liboqs 0.10+). - Protect the secret key file with scrypt (memory-hard) + a random per-file salt instead of feeding the passphrase straight into HKDF. - Authenticate the version header and KEM ciphertext as GCM AAD. - Wipe key buffers with OPENSSL_cleanse, including the previously un-zeroed passphrase-derived key buffers. - Allocate the KEM shared-secret buffer from kem->length_shared_secret rather than assuming 32 bytes. - Remove partial output files when encryption/decryption fails. Correctness - Make decryption truly streaming: it no longer loads the whole ciphertext into memory (the README's constant-memory claim now holds). - Implement --force: without it, Qsafe prompts before overwriting an existing output file (previously the flag was a no-op). - Fix the progress bar (it only rendered at 100%) and guard against a division by zero on empty input. - Make directory processing recursive and skip the secret key file. Build, tests, docs - Harden the Makefile (-Wextra, -fstack-protector-strong, _FORTIFY_SOURCE, -std=c11) and build the binary before `make test`. - Add a GitHub Actions CI workflow (build liboqs, build, run tests). - Expand the unit/integration suites: scrypt KDF, salt randomness, empty/single-chunk/multi-chunk round-trips, recursive directories, KEM-ciphertext tampering, argument validation. - Rewrite README for accuracy; remove the stale docs/ReadMe.md. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Fix the core data-loss bug where every encrypt regenerated and overwrote the keypair, making previously encrypted files unrecoverable. Qsafe now follows a true public-key workflow with a one-time keygen step. - keygen: generate the ML-KEM-1024 keypair once; secret_key.bin is passphrase-wrapped (0600), secret_key.bin.pub is stored in the clear - encrypt uses only the public key (no passphrase); decrypt uses the secret key. Encrypting never invalidates earlier ciphertexts - new QSAFE004 format: nonce moved to the front + 16-byte tag hold-back so decryption streams from a pipe without seeking - stdin/stdout piping via '-' (composes with tar, ssh, etc.) - encrypted+authenticated metadata block preserves original name, mode, and mtime; decrypt can restore into a directory by original name - auto-detect file vs dir (drop the trailing file|dir arg); optional output paths with sensible defaults - passphrase via interactive no-echo prompt, $QSAFE_PASSPHRASE, or --passphrase-file instead of being required on the command line - rename binary crypto-v2 -> qsafe; add make install/uninstall - cross-platform Makefile + setup.sh (macOS Homebrew and Linux) - update unit + integration tests and docs; full suite passes
glibc restricts to strict ISO C with -std=c11, hiding mode_t, PATH_MAX, fileno, tcgetattr, realpath, and utime. macOS exposes them by default, so the build only failed in CI. Define _DEFAULT_SOURCE at the top of both translation units and add <sys/types.h> for mode_t.
GNU stat -f means --file-system and succeeds with the wrong output, so the BSD-first fallback never ran. Try GNU 'stat -c %a' first, then BSD 'stat -f %Lp'.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes the core data-loss bug where every
encryptregenerated and overwrote the keypair, making previously encrypted files unrecoverable. Qsafe now follows a true public-key workflow with a one-timekeygenstep, plus a set of usability and portability improvements.The critical fix — durable, asymmetric keys
keygencommand generates the ML-KEM-1024 keypair once:secret_key.binis passphrase-wrapped (0600),secret_key.bin.pubis stored in the clear.encryptuses only the public key (no passphrase);decryptuses the secret key. Encrypting a second file no longer invalidates earlier ciphertexts.Usability
file|dirargument is gone.report.pdf→report.pdf.qsafe, and back).$QSAFE_PASSPHRASE, or--passphrase-fileinstead of being required on the command line. Options may appear before or after the command.New capabilities (format bump to
QSAFE004)-(composes withtar,ssh, …). Drove moving the nonce to the front and recovering the GCM tag via 16-byte hold-back, so decryption streams without seeking.decrypt file.qsafe ./dir/restores into the directory under the original name.Build / platform
crypto-v2→qsafe; addedmake install/uninstall(honorsPREFIX/DESTDIR).openssl@3/liboqson macOS, falls back to system paths on Linux.setup.shhandles both.Tests / docs
test.sh(keygen, pipes, dir mode, filename/permission restore, rejection cases). README and flow diagram updated.Breaking changes
QSAFE003files cannot be read by 4.0 — decrypt them with a 3.x build first.file|dirarg, optional output paths, binary renamed toqsafe.