Security Recommendations#
This page is the practical answer to:
“Which Epicrypt option should I choose for a new application?”
Quick Picks#
If you are starting fresh, prefer these defaults:
Password hashing:
PasswordHasherwithSecurityProfile::MODERNPassword upgrades:
verifyAndRehash()App payload encryption:
DataProtection\StringProtectorLarge file encryption:
DataProtection\FileProtectorEnvelope-style protected storage:
DataProtection\EnvelopeProtectorAPI tokens with one shared secret:
Token\Jwt\SymmetricJwtAPI tokens with separate signer/verifier trust:
Token\Jwt\AsymmetricJwtRevocable random bearer tokens:
Token\Opaque\OpaqueTokenSmall signed action/reset payloads:
Token\Payload\SignedPayloadBrowser workflow tokens:
Securitydomain helpers such asPasswordResetTokenandSignedUrlNew ciphertext formats: modern
DataProtectionAPIs
Public Surface First#
For new applications, start from these domains first:
PasswordTokenDataProtectionSecurity
Treat these as lower-level or advanced:
Cryptofor direct primitive control
Choose the Right Tool#
Passwords#
Use:
PasswordHasherfor stored user passwordsPasswordStrengthfor quality feedbackverifyAndRehash()when you want login-time hash upgrades
Prefer:
SecurityProfile::MODERNdefault Argon2id-based hashing
Avoid:
custom password hashing logic
storing app secrets as password hashes when you actually need reversible protection
Secrets and Stored Sensitive Values#
Use:
WrappedSecretManagerfor secrets that must be unwrapped laterSecureSecretSerializerfor structured secret-bearing dataKeyRingplus rewrap helpers during rotation windows
Prefer:
one active master secret
short fallback windows for previous key versions
Protected Data#
Use:
StringProtectorfor ordinary application payloadsEnvelopeProtectorwhen you want a structured encoded envelopeFileProtectorfor large files and streaming-safe encryptionFileProtector::reencryptWithAnyKey()when rotating protected files across key versions
Prefer:
re-encrypting artifacts under the active key when fallback keys match
decryptWithAnyKey()orreencryptWithAnyKey()only during rotation windowsresult helpers like
decryptWithAnyKeyResult()when rotation code needs to know which key matched
Avoid:
using low-level crypto primitives directly unless you really need them
Tokens#
Use:
SymmetricJwtwhen issuer and verifier share one secretAsymmetricJwtwhen the signer should keep a private key and verifiers should only need public keysOpaqueTokenwhen token contents should stay server-sideSignedPayloadfor compact signed internal flows
Prefer:
kidplus key-set mode when rotating JWT signing keysKeyRing-based verification helpers during short transition windowsverifyWithAnyKeyResult()when callers need to know whether a fallback key matched
Avoid:
mixing symmetric and asymmetric expectations in one verification path
exposing sensitive state in JWT claims when opaque tokens fit better
Crypto Primitives#
Use:
AeadCipherfor authenticated encryption of short payloadsSecretBoxCipherwhen you specifically want secretbox semanticsSecretStreamorFileProtectorfor large file workflowsMacfor shared-secret integritySignaturefor public/private signature verification
Prefer:
AeadAlgorithm::XCHACHA20_POLY1305_IETFfor new AEAD usagehigher-level
DataProtectionAPIs unless the primitive is truly what you need
Key Material and Derivation#
Use:
KeyMaterialGeneratorfor fresh random keysKeyDeriverfor derived keyspurpose-aware key generation helpers when available
Prefer:
generated keys for encryption keys
derived keys when the design specifically needs deterministic derivation
explicit context/info separation for derived subkeys
Key Rotation#
Use key-ring helpers during planned key rollover.
Prefer this pattern:
issue new artifacts with the active key
keep decode/verify paths able to read active and fallback keys during rollout
re-encrypt or re-issue under the active key when a fallback key matches
remove fallback keys after the rollover window closes
In particular:
prefer
StringProtectorandEnvelopeProtectorfor new protected datafollow the key rotation cookbook for active-key and fallback-key rollout patterns
Binary vs Base64URL#
Most public Epicrypt APIs expect Base64URL strings by default.
Use explicit context flags only when you are intentionally passing raw binary values, for example:
key_is_binarynonce_is_binarysalt_is_binary
When possible, keep one format per application boundary instead of mixing both styles in the same layer.
Simple Rule of Thumb#
If a higher-level
Password,Security,TokenorDataProtectionAPI fits your use case, choose it first.Reach for
Cryptoprimitives only when you need direct cryptographic control.Prefer modern defaults and active-key rotation.