Software Engineering
Encrypting Sensitive Application Data in .NET
Application encryption is a key-management and data-lifecycle system, not a call to an encryption API. The design must preserve integrity, rotation, recovery and the ability to find data safely.

Start with the attacker encryption should stop
Disk and managed-database encryption protects lost media and some infrastructure access. TLS protects transit. Application-level encryption can protect selected fields from database readers and backups, but not from a compromised application that can decrypt them. Define the threat before adding irreversible complexity.
Control layers
| Control | Protects | Does not protect |
|---|---|---|
| Storage encryption | Physical media/snapshots | Authorised database queries |
| TLS | Network transit | Endpoints and logs |
| Field encryption | Selected stored values | Compromised application identity |
| Hashing | Verification without recovery | Low-entropy values without keyed design |
| Tokenisation | Reduces sensitive-data footprint | Token service compromise |

Use authenticated encryption
Encryption without integrity allows ciphertext modification. Use a modern authenticated mode such as AES-GCM through vetted .NET libraries. Generate a unique nonce as required by the algorithm and never reuse a nonce with the same key. Store algorithm, key ID, nonce, ciphertext and tag in a versioned envelope.
Do not invent formats or derive keys by trimming passwords. Passwords need a password-hashing KDF; searchable deterministic values need a separate threat-aware design.
Envelope encryption makes rotation possible
Generate data-encryption keys and wrap them with a key-encryption key held in Key Vault/HSM. The database stores wrapped key material with ciphertext. Rotating the wrapping key can rewrap data keys without decrypting every large value; rotating data keys requires re-encryption.
Retain old key versions while ciphertext references them. Disabling a key before migration makes data unavailable. Key deletion is a data-destruction operation.
Search and encryption conflict
Randomised encryption prevents equality indexes. If lookup by email or reference is essential, store a keyed HMAC blind index separately, normalised deliberately. It leaks equality patterns and low-entropy domains may still be guessable if the key is compromised.
Never reuse the encryption key for hashing. Range and substring search usually require redesigned workflows or specialised systems; “encrypt the column” cannot preserve every query.
Bind ciphertext to context
Use associated authenticated data for tenant, record and field identity so ciphertext copied to another row cannot decrypt as valid there. Associated data is authenticated but not encrypted, so do not put secrets inside it.
Tenant-specific keys can reduce blast radius but increase availability, mapping and rotation operations. Promise only the isolation the key hierarchy actually enforces.
Decryption boundaries matter
Decrypt as late as possible and avoid materialising plaintext in logs, exceptions, analytics, caches or search indexes. Restrict application operations that can retrieve plaintext and audit high-risk access.
Backups contain ciphertext and wrapped keys; recovery must also restore key access and mapping. Test restore in an isolated environment rather than assuming Key Vault retention aligns with database retention.
Rotation is a resumable migration
Version every envelope, read old and new formats, write only the new format, migrate in bounded idempotent batches, verify, then retire old keys. Expect mixed versions during rolling deployments and retries.
Monitor remaining ciphertext by key ID without logging values. Have a rollback path that retains old decryption capability.
Production checklist
- Document threat model and data classification.
- Minimise or tokenise before encrypting.
- Use authenticated encryption and unique nonces.
- Store a versioned self-describing envelope.
- Separate data and key-encryption keys.
- Bind tenant/record context as authenticated data.
- Design search leakage explicitly.
- Keep plaintext out of telemetry and caches.
- Rotate through resumable mixed-version migration.
- Test backup restore with historical keys.
Encryption does not replace authorisation or minimisation
Application-level encryption limits what a database reader can understand. It does not stop an authorised application path decrypting the wrong tenant's record, an over-privileged support user requesting plaintext or a compromised process reading values after decryption.
Collect less, retain it for less time and enforce resource-level access before adding cryptography. Encryption can reduce breach impact, but it also makes deletion, search, support and recovery more complicated. A field with no justified purpose is safer absent than encrypted forever.
Keys need identities, versions and separated custody
Never store the data-encryption key beside ciphertext under the same permissions. Envelope encryption uses a data key for content and a key-encryption key in a managed service to protect that key. Store key identifier, algorithm and version with the encrypted envelope so future code knows how to decrypt it.
Separate permission to read ciphertext from permission to unwrap keys where the threat model justifies it. Keep development and production key hierarchies distinct. A copied production database should remain unintelligible in a lower environment rather than becoming realistic test data.
Key backup, deletion protection and recovery are part of availability. Permanently deleting a required key is permanent data loss. Rehearse restoration and document which roles can rotate, disable or destroy keys.
Nonce reuse can destroy otherwise strong encryption
Authenticated-encryption modes require a nonce or IV with strict uniqueness properties under one key. It is usually stored openly beside ciphertext; secrecy is not its job. Reusing it with algorithms such as AES-GCM can reveal relationships between plaintexts and undermine authentication.
Generate nonces using a cryptographically secure mechanism and follow the algorithm's required size. Do not derive them from record IDs or timestamps without a proven construction. Store the authentication tag and reject the entire value when verification fails-never return partially decrypted data.
Associated data can bind ciphertext to tenant, record type and field without encrypting that context. This prevents a valid encrypted value being copied into a different context and accepted as legitimate.
Searchable encryption is mostly a leakage trade-off
Randomised encryption intentionally gives the same plaintext different ciphertext, so equality queries and ordinary indexes stop working. Deterministic encryption permits equality lookup but reveals repeated values and frequency. Low-entropy fields such as postcode or status can be guessed even without direct decryption.
A keyed blind index can support exact matching while separating search material from ciphertext, but it still leaks equality and needs its own key lifecycle. Prefix, range and full-text search require more specialised schemes or a separate protected projection.
Do not weaken encryption merely to preserve every existing query. Identify which searches are genuinely required, document leakage and restrict access to indexes. Sometimes tokenisation or moving the operation behind a narrowly trusted service is the better design.
Rotation is a live data migration
Changing the active key only protects new writes. Historical ciphertext retains the old key version until re-encrypted. Readers should understand both versions while a resumable background process migrates records in bounded batches.
Make the job idempotent, checkpoint progress and verify decryption before replacing the stored envelope. Do not hold a huge transaction or disable normal writes. A concurrent update needs optimistic concurrency so migration cannot overwrite newer business data.
Compromise rotation differs from routine rotation. If the old key may be exposed, prioritise containment, audit decrypt activity and decide whether re-encryption meaningfully reduces risk after plaintext may already have escaped.
Design plaintext boundaries for operations
Decrypt as late as possible and discard plaintext references quickly, while recognising managed memory is not a guaranteed secure enclave. Avoid placing decrypted values in exceptions, tracing, analytics, caches and exports. Redaction should allow known-safe fields rather than attempting to recognise every secret.
Background jobs and support tools require the same boundary. A report containing decrypted data becomes another sensitive store with its own access and retention. Restrict bulk decrypt and alert on unusual volume.
Backups preserve ciphertext, so successful restore also depends on historical keys and permissions. Test application recovery end to end; restoring rows without their key hierarchy is not recovery.
Cryptography needs a format and retirement plan
Store a self-describing envelope containing format version, algorithm, key reference, nonce, tag and ciphertext. That allows algorithm migration without guessing from data length or deployment date. Validate every field before use and fail closed on unknown formats.
Use maintained platform cryptography rather than designing algorithms. Protect key-service availability with bounded caching where appropriate, but understand that caching extends how long revoked key material remains usable inside processes.
The final test is not “is the column unreadable?” It is whether authorised journeys, rotation, deletion, incident response and disaster recovery still work while unauthorised paths cannot obtain meaningful plaintext.
Finally, treat cryptographic failure as an incident class. Authentication-tag failures may indicate corruption, wrong context or tampering; count and investigate them without leaking ciphertext or keys. Silently returning null converts evidence into hidden data loss.
Related C3 Software guides
Frequently asked questions
Is database encryption at rest enough?
It protects media and infrastructure scenarios, not authorised database readers or leaked query results.
Should encrypted data be searchable?
Only through a deliberate leakage-aware index such as a keyed HMAC for exact lookup.
Why use authenticated encryption?
It detects ciphertext or context modification as well as hiding plaintext.
What happens when a key is deleted?
Referenced ciphertext becomes permanently unreadable; key deletion must be governed like data destruction.
Protect data without losing recoverability
For an encryption design review, talk to C3 Software.