Skip to main content

The encryption landscape

Type: ExplanationCreated: Team: Security
draft

A map of encryption management

This is a complete map of encryption management — every area worth having on your radar — organized so you can see how the pieces fit together. From here you can drill into whichever part matters for Skapp. Each area is kept tight.

1. Start with the threat model

Before any technology, one question decides your whole approach: what are you protecting against? Encryption choices only make sense relative to a threat. The main ones:

  • Stolen physical media or a raw DB dump — someone walks off with a disk or grabs a backup file. Encryption at rest solves this.
  • Network interception — someone sniffs traffic between services or from the client. Encryption in transit solves this.
  • Compromised application or valid credentials — an attacker gets into your app or a DB account. At-rest encryption does nothing here; the app decrypts normally. You need field-level encryption, access control, and least privilege.
  • Malicious or curious insider — a DBA or a developer with prod access. This calls for application-level or column-level encryption plus separation of key access.
  • Cloud provider access — do you trust your cloud provider never to see your plaintext? This is what customer-managed keys / BYOK address.
warning

The mistake to avoid is treating "we enabled encryption" as one binary switch. Which threat each layer addresses is the real question.

2. The three states of data

Encryption is organized around where the data is at a given moment. There are three states:

  • In transit — moving across a network. Protected with TLS (the "S" in HTTPS). It covers client-to-server traffic and service-to-service traffic alike — for example, your app talking to its database, or to object storage like S3. Internal traffic counts too: "it's inside our private network" is not a reason to skip it. A stricter version, mTLS, makes both sides prove who they are, not just the server — common inside service meshes.
  • At rest — sitting in storage. This is the layered one, and it gets its own section below (section 3).
  • In use — being processed in memory as plaintext. The hardest and newest area. The approaches here — confidential computing (encrypted memory enclaves like AWS Nitro Enclaves), homomorphic encryption (doing the maths directly on encrypted data), and secure multi-party computation — are mostly still impractical for everyday use. For most products you can set this aside; it only matters for very high-sensitivity workloads.

3. Encryption at rest — the four layers

This is where people miss things, because "encrypted at rest" can mean very different depths:

  • Layer 1 — Full-disk / volume encryption. The storage volume is encrypted (for example, encrypted EBS or encrypted RDS storage).
    • Protects against: stolen physical disks or imperfect disposal — in AWS, a failed drive sent off for RMA, a decommissioned drive that wasn't wiped cleanly, or insider/physical access at the data center.
    • Transparent to anything accessing the disk through the normal running system.
    • Key limitation: if someone gains remote access to your running EC2/RDS instance — via compromised credentials, SSH, a hacked app, or SQL injection — they read the data through the system, which sees plaintext.
    • Trade-off: the cheap default, but the weakest in threat coverage (only physical theft).
  • Layer 2 — Database-level encryption (TDE, Transparent Data Encryption). The database engine encrypts its own data files — tablespaces, logs, and backups — as it writes them (MySQL/InnoDB tablespace encryption; on managed RDS this is largely bundled with storage encryption).
    • Protects against: the data leaking when a database file leaves the encrypted volume but stays a database file — a backup or dump copied to S3 or elsewhere, or a raw .ibd tablespace file copied off to an unencrypted location. The encryption travels with the file, so it stays ciphertext wherever it lands.
    • Transparent to queries — you SELECT and get plaintext.
    • Key limitation: anyone with a valid DB connection still sees everything, because the engine decrypts transparently for queries — so it does nothing against a logical/remote attacker.
    • Trade-off: protection now travels with the database files/backups rather than ending at the volume boundary, but on RDS it largely overlaps with Layer 1, so running both adds little extra threat coverage.
  • Layer 3 — Column / field-level encryption. Specific sensitive columns are encrypted while the rest of the table stays plaintext (used for things like national ID numbers, salary, and health fields).
    • Protects against: a DB dump or a DB-level attacker — anyone with a valid DB connection, a DBA, or SQL injection reading the table — now sees only ciphertext for those columns, not plaintext. This is the first layer that defends against a logical/remote attacker, not just physical media.
    • Transparent to queries only for the non-encrypted columns; the encrypted columns come back as ciphertext unless your app decrypts them.
    • Key limitation: you lose easy querying on those columns — searching, sorting, and indexing on them break (see section 7) — and you now own key management.
    • Trade-off: real protection against DB compromise and insiders for the chosen fields, but at the cost of queryability on them and the operational burden of managing keys.
    • An implementation example - You use the database engine's built-in crypto functions and pass the key into the query. In MySQL that's AES_ENCRYPT() / AES_DECRYPT():
    • Note - The defining trait: the key (@key) and the plaintext both travel to the DB. The app sends plaintext, the DB encrypts it, the DB decrypts on read. The key lives in the DB session (Key leaks into logs) — which is exactly why a fully-compromised DB can betray you and This is why Layer 3 is less common in greenfield apps than Layer 4.
-- column stored as VARBINARY / BLOB
INSERT INTO ppl_employee (national_id)
VALUES (AES_ENCRYPT('912345678V', @key));

SELECT AES_DECRYPT(national_id, @key) AS national_id
FROM ppl_employee;
  • Layer 4 — Application-level encryption. Your app encrypts the data before it ever reaches the database; the database only ever stores ciphertext and never holds a key.
    • Protects against: the strongest coverage against DB compromise and insiders — since the key never lives in the database tier, a full DB dump, a DBA, SQL injection, or even someone with complete database access only ever sees ciphertext. The database is treated as an untrusted store.
    • Transparent to nothing at the DB level — the database only ever holds ciphertext; only your app, holding the key, can turn it back into plaintext.
    • Key limitation: it breaks searching, sorting, and indexing on those fields entirely, and you fully own key management (now even more critical, since the DB can't help you at all).
    • Trade-off: the strongest protection of all four layers, but the most complex to build and operate.
tip

The key insight is that these layers stack, and each higher layer defends against a stricter threat. Most products use Layer 1 and 2 broadly (managed by the cloud) and reach for Layer 3 and 4 selectively, on the few genuinely sensitive fields.

4. The crypto primitives

You don't need to be a cryptographer, but three building blocks come up constantly:

  • Symmetric encryption (AES, usually AES-256-GCM) — one key both encrypts and decrypts. It's fast, so it handles the actual bulk data. GCM mode also provides integrity (it detects tampering), which is why it's preferred over older modes like CBC.
  • Asymmetric encryption (RSA, elliptic curve) — a public/private key pair. It's slower, so it's used for key exchange, signing, and TLS handshakes — not for bulk data.
  • Hashing (SHA-256; and for passwords specifically, bcrypt, argon2, or scrypt) — one-way, and not encryption. The critical distinction: passwords are hashed, never encrypted. If you can decrypt a stored password, you're doing it wrong. Hashing also powers integrity checks and pseudonymisation tokens.
tip

The confusion worth nailing: encryption is reversible (with the key); hashing is not. Use encryption when you need the data back, and hashing when you only ever need to verify a match.