Skip to content

Data Encryption Guide -- Encryption at Rest, in Transit, Key Management & TLS Configuration

DodaTech Updated 2026-06-22 8 min read

In this tutorial, you'll learn about Data Encryption Guide. We cover key concepts, practical examples, and best practices.

Data encryption transforms readable data into ciphertext using cryptographic algorithms -- protecting information at rest on storage devices, in transit across networks, and during processing from unauthorized access throughout its lifecycle.

What You'll Learn

You will learn to implement AES-256 encryption for files and databases, configure TLS 1.3 for secure communication, manage encryption keys with HSMs and cloud KMS, and meet GDPR and PCI DSS encryption requirements.

Why It Matters

Data breaches exposed 22 billion records in 2024. Encrypted data is considered not breached in 41 states under safe harbor laws. Encryption reduces breach costs by an average of $360,000 and is mandatory for PCI DSS and GDPR compliance.

Real-World Use

A healthcare SaaS provider encrypts all patient data with AES-256-GCM at rest using envelope encryption with AWS KMS. When a forensic auditor inspects a compromised database, the encrypted columns appear as binary garbage -- zero data exposure despite full database access.

Encryption Methods Compared

Method Algorithm Key Size Use Case Performance FIPS 140-2
AES-256-GCM Symmetric 256-bit Data at rest, files Very fast Yes
ChaCha20-Poly1305 Symmetric 256-bit Mobile, TLS fallback Very fast Yes (2024)
RSA Asymmetric 2048-4096-bit Key exchange, signatures Slow Yes
ECDSA Asymmetric 256-521-bit Signatures, TLS Fast Yes
ECDH Key agreement 256-521-bit Key exchange Fast Yes
Argon2id Password hashing Variable Key derivation Moderate No (NIST approved)

File Encryption with OpenSSL

# Encrypt a file with AES-256-GCM
openssl enc -aes-256-gcm -pbkdf2 -iter 100000 \
  -salt -in sensitive-data.txt -out sensitive-data.enc

# Decrypt the file
openssl enc -d -aes-256-gcm -pbkdf2 -iter 100000 \
  -in sensitive-data.enc -out sensitive-data-decrypted.txt

# Expected output: no output if successful
# Verify decryption
diff sensitive-data.txt sensitive-data-decrypted.txt
# Expected: no output (files match)

Expected behavior: OpenSSL encrypts the file with AES-256 in GCM mode using a key derived from the password via PBKDF2 with 100,000 iterations. The output includes the salt and authentication tag. Decryption fails if the file is tampered with.

Encrypt a Directory with tar and GPG

# Create encrypted archive of a directory
tar czf - important-documents/ | \
  gpg --symmetric --cipher-algo AES256 --batch \
  --passphrase "$ENCRYPTION_PASSPHRASE" \
  -o documents.tar.gz.gpg

# Decrypt and extract
gpg --decrypt documents.tar.gz.gpg | tar xzf -

# Expected output for decryption:
# Enter passphrase:
# (file extracted to current directory)

# Verify archive integrity
tar tzf documents.tar.gz 2>/dev/null || \
  echo "Archive is encrypted -- decrypt first"

Expected behavior: The directory is tarred, compressed, and symmetrically encrypted with AES-256 using GPG. Decryption requires the correct passphrase. Tampered archives fail during decryption with GPG error messages.

TLS 1.3 Configuration for NGINX

# /etc/nginx/nginx.conf -- modern TLS configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers on;
ssl_ecdh_curve X25519:prime256v1:secp384r1;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_session_tickets off;

# Enable HSTS
add_header Strict-Transport-Security "max-age=63072000" always;

# OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 1.1.1.1 8.8.8.8 valid=300s;
resolver_timeout 5s;

# Certificate paths
ssl_certificate /etc/ssl/certs/dodatech.com.pem;
ssl_certificate_key /etc/ssl/private/dodatech.com.key;

server {
    listen 443 ssl http2;
    server_name dodatech.com;

    location / {
        root /var/www/html;
        add_header X-Content-Type-Options nosniff;
        add_header X-Frame-Options DENY;
    }
}

Expected behavior: The server supports TLS 1.2 and 1.3 with strong modern ciphers. HSTS is enabled for two years. OCSP stapling improves handshake performance. The configuration earns an A+ rating on SSL Labs testing.

Database Encryption at Rest with Envelope Encryption

import os
import boto3
from cryptography.fernet import Fernet
from cryptography.hazmat.primitives.ciphers.aead import AESGCM

class DatabaseEncryptionService:
    """Envelope encryption with AWS KMS for database fields."""

    def __init__(self, kms_key_id):
        self.kms = boto3.client("kms")
        self.kms_key_id = kms_key_id

    def generate_data_key(self):
        """Generate a data key encrypted by KMS."""
        response = self.kms.generate_data_key(
            KeyId=self.kms_key_id,
            KeySpec="AES_256"
        )
        return {
            "ciphertext_blob": response["CiphertextBlob"],
            "plaintext_key": response["Plaintext"]
        }

    def encrypt_field(self, plaintext, data_key):
        """Encrypt a field using AES-256-GCM."""
        aesgcm = AESGCM(data_key["plaintext_key"])
        nonce = os.urandom(12)
        ciphertext = aesgcm.encrypt(nonce, plaintext.encode(), None)
        return {
            "ciphertext": ciphertext,
            "nonce": nonce,
            "key_ciphertext": data_key["ciphertext_blob"]
        }

    def decrypt_field(self, encrypted):
        """Decrypt a field by first decrypting the data key."""
        response = self.kms.decrypt(
            CiphertextBlob=encrypted["key_ciphertext"]
        )
        aesgcm = AESGCM(response["Plaintext"])
        plaintext = aesgcm.decrypt(
            encrypted["nonce"],
            encrypted["ciphertext"],
            None
        )
        return plaintext.decode()

# Usage
enc_service = DatabaseEncryptionService("alias/dodatech-db-key")
data_key = enc_service.generate_data_key()

# Encrypt a sensitive field
ssn_encrypted = enc_service.encrypt_field("123-45-6789", data_key)
print(f"Encrypted SSN: {ssn_encrypted['ciphertext'][:16]}...")
# Expected output: Encrypted SSN: b'\x12\x34...' (garbled)

# Decrypt
ssn_decrypted = enc_service.decrypt_field(ssn_encrypted)
print(f"Decrypted SSN: {ssn_decrypted}")
# Expected output: Decrypted SSN: 123-45-6789

Expected behavior: A unique data encryption key (DEK) is generated for each encryption operation. The DEK is encrypted by KMS and stored alongside the ciphertext. The KMS master key never leaves AWS. Decryption requires KMS access, providing audit logging of all decryption operations.

Key Management with HashiCorp Vault

# Vault transit engine configuration for encryption-as-a-service
# Enable transit engine on the encryption path
vault secrets enable transit

# Create an encryption key
vault write -f transit/keys/database-key \
  type=aes256-gcm96 \
  exportable=false \
  derived=true

# Encrypt data via API
vault write transit/encrypt/database-key \
  plaintext=$(echo -n "sensitive-patient-data" | base64)

# Expected output:
# Key        Value
# ---        -----
# ciphertext vault:v1:abc123def456...

# Decrypt data
vault write transit/decrypt/database-key \
  ciphertext=vault:v1:abc123def456...

# Expected output:
# Key          Value
# ---          -----
# plaintext    c2Vuc2l0aXZlLXBhdGllbnQtZGF0YQ==

Expected behavior: Vault acts as an encryption-as-a-service gateway. Applications never see raw encryption keys. All encryption and decryption operations pass through Vault, providing centralized audit logging, key rotation, and access control.

End-to-End Encryption Architecture

graph TD
    A[Client Application] --> B{TLS 1.3}
    B --> C[API Gateway]
    C --> D[Application Server]
    D --> E[Application-Level Encryption]
    E --> F[Encrypted Data Written]
    F --> G[(Encrypted Database)]
    E --> H[Vault Transit Engine]
    H --> I[KMS Master Key]
    F --> J[(S3 Encrypted Backups)]
    style A fill:#4a90d9,stroke:#fff,color:#fff
    style G fill:#e67e22,stroke:#fff,color:#fff
    style I fill:#e74c3c,stroke:#fff,color:#fff

Certificate Generation with certbot

# Generate TLS certificate with Let's Encrypt
certbot certonly --webroot -w /var/www/html \
  -d dodatech.com -d www.dodatech.com \
  --rsa-key-size 4096 \
  --must-staple \
  --agree-tos --email admin@dodatech.com

# Expected output:
# Successfully received certificate.
# Certificate is saved at:
#   /etc/letsencrypt/live/dodatech.com/fullchain.pem
#   /etc/letsencrypt/live/dodatech.com/privkey.pem

# Verify certificate details
openssl x509 -in /etc/letsencrypt/live/dodatech.com/fullchain.pem \
  -text -noout | grep -E "(Subject:|Not Before|Not After|DNS:)"
# Expected output:
# Subject: CN = dodatech.com
# Not Before: Jun 10 00:00:00 2026 GMT
# Not After : Sep 10 00:00:00 2026 GMT
# DNS:dodatech.com, DNS:www.dodatech.com

Expected behavior: Certbot obtains a 90-day certificate from Let's Encrypt with automatic renewal configured via systemd timer or cron. The auto-renewal hook reloads NGINX to pick up the new certificate.

Common Errors

  1. Using outdated or weak ciphers -- RC4, DES, and 3DES are completely broken. TLS 1.0 and 1.1 are deprecated. Modern encryption requires TLS 1.2 minimum, AES-256-GCM or ChaCha20-Poly1305, and ECDHE key exchange for perfect forward secrecy.

  2. Hardcoding encryption keys in source code -- Keys committed to Git repositories are compromised permanently. Use an HSM, cloud KMS, or Vault for key storage. Never store encryption keys in config files, environment variables, or code.

  3. Not using authenticated encryption modes -- AES-ECB and AES-CBC do not provide integrity verification. An attacker can modify ciphertext undetected. Always use authenticated modes like AES-GCM or ChaCha20-Poly1305 that include a MAC.

  4. Ignoring key rotation requirements -- Static keys that never rotate create a single point of failure. If a key is compromised, all data encrypted with it must be re-encrypted. Implement automatic key rotation and re-encryption pipelines.

  5. Encrypting database columns but not files or backups -- Column-level encryption protects structured data, but database dump files, WAL logs, and backups may contain plaintext data. Apply encryption at all layers: disk, file, column, and backup.

  6. Poor passphrase entropy for key derivation -- Weak passwords used for GPG or OpenSSL file encryption can be brute-forced. Use a passphrase with at least 30 characters of mixed entropy, or better, use key-based encryption with asymmetric keys.

Practice Questions

  1. What is the difference between encryption in transit and encryption at rest? Encryption in transit protects data moving over networks using TLS. Encryption at rest protects stored data using disk encryption or column-level encryption. Both are required for compliance. In transit prevents eavesdropping; at rest prevents unauthorized data access from storage.

  2. How does envelope encryption work? Envelope encryption uses a Key Encryption Key (KEK) to encrypt Data Encryption Keys (DEKs). Each piece of data gets a unique DEK. The DEK is encrypted by the KEK and stored with the data. The KEK is stored in a secure KMS. This enables key rotation without re-encrypting all data.

  3. What is perfect forward secrecy and why does it matter? Perfect forward secrecy ensures that compromising the server's long-term private key does not expose past session keys. ECDHE key exchange generates ephemeral session keys that are never stored. Without PFS, an attacker who records traffic now and later steals the private key can decrypt all recorded sessions.

  4. Why is TLS 1.3 faster than TLS 1.2? TLS 1.3 reduces the handshake from two round trips to one (and zero for resumed sessions). It removes insecure options, uses only AEAD ciphers, and encrypts more of the handshake. Connection setup is 33-50% faster.

  5. Challenge: Set up a complete encryption pipeline. Deploy Vault in dev mode, enable the transit engine, create an AES-256-GCM key. Write a Python script that encrypts a JSON file using Vault's transit API, stores the ciphertext, then decrypts and verifies it. Rotate the key and verify old data is still decryptable.

Mini Project

Build a secure file sharing application with end-to-end encryption. Use Python with PyCryptodome for client-side AES-256-GCM encryption, Vault for key management via API, and Flask for the web layer. Files are encrypted before upload and decrypted only in the browser using the Web Crypto API. No plaintext data touches the server.

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro