feat(crypto): add password-based encryption (PasswordCipher)#20
Merged
Conversation
…+ AES-GCM) - Add PasswordCipher static class: Encrypt/Decrypt byte[], EncryptString/DecryptString (base64) - Add PasswordDecryptionException (sealed, extends CryptographicException) for wrong password or tampered data - AES-256-GCM with AAD-bound authentication; wrong password and ciphertext/header tampering all throw PasswordDecryptionException - Encrypt produces unique blobs per call via random salt + nonce - PbkdfCost defaults to Moderate when omitted
The envelope stores parallelism in a single byte, so a value above 255 would truncate silently and produce an undecryptable blob (the key is derived with the real lane count on encrypt but the envelope records the truncated one). Guard it with ArgumentOutOfRangeException.ThrowIfGreaterThan up front. Add tests for the guard plus empty-plaintext and non-ASCII-password round-trips.
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
A static password-based encryption primitive in
SquidStd.Crypto:PasswordCipherencrypts a payload under a password (Argon2id derives the key, AES-256-GCM seals it) and produces a self-describing, versioned, AAD-bound envelope — decryption needs only the password and the blob. Fills the gap betweenCryptoUtils(raw key) andISecretProtector(app-key/KMS).API
Wrong password or tampered data →
PasswordDecryptionException.Architecture
PasswordEnvelope+PasswordEnvelopeCodec) — Terminal.Gui-free, unit-tested as plain data.PasswordKeyDerivation, BouncyCastle) — same params/version as the existing vault.PasswordCipher) — AES-256-GCM, random salt+nonce per call.PbkdfCostpresets (Interactive / Moderate / Sensitive) + custom.Envelope
SPBEv1magic(4) | version(1) | iterations(4) | memoryKib(4) | parallelism(1) | salt(16) | nonce(12) | tag(16) | ciphertextThe 42 bytes before the tag are the GCM AAD, so version (no downgrade), KDF cost, salt and nonce are all authenticated.
Security notes
Encrypt— no nonce reuse under a fixed key (the key also varies by salt).PbkdfCostrejectsparallelism > 255(the envelope byte field) to avoid silent truncation.Test plan