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.

Application-level encryption and key rotation

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

ControlProtectsDoes not protect
Storage encryptionPhysical media/snapshotsAuthorised database queries
TLSNetwork transitEndpoints and logs
Field encryptionSelected stored valuesCompromised application identity
HashingVerification without recoveryLow-entropy values without keyed design
TokenisationReduces sensitive-data footprintToken service compromise
Sensitive records protected by layered encryption
Envelope encryption keeps data keys close to ciphertext and root key authority outside the database.

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.