S
SovereignShield
Back to Blog & Guides/GDPR Data Encryption at Rest & in Transit: A Developer's Implementation Guide
#GDPR#Encryption#Security#Node.js#Cryptography

GDPR Data Encryption at Rest & in Transit: A Developer's Implementation Guide

Learn how to implement AES-256-GCM field-level database encryption and enforce TLS 1.3 cipher suites for GDPR Articles 32 and 25 compliance.

SovereignShield Engineering

Executive Summary & GDPR Context

Article 32 of the General Data Protection Regulation (GDPR) mandates “Security of Processing,” explicitly calling out pseudonymisation and encryption of personal data as state-of-the-art technical measures. Furthermore, Article 25 (Data Protection by Design and by Default) requires engineers to embed encryption primitives directly into the architecture rather than relying on perimeter security alone.

This guide provides concrete, copy-pasteable implementation patterns for:

  1. Encryption at Rest: Field-level encryption (FLE) using AES-256-GCM with authenticated key rotation.
  2. Encryption in Transit: Strict TLS 1.3 server configuration and HTTP Strict Transport Security (HSTS) header enforcement.

1. Field-Level Encryption at Rest (AES-256-GCM)

While disk encryption (LUKS, AWS EBS Encryption) protects against physical theft of hard drives, it does not protect against SQL injection, database compromise, or rogue internal database administrators. Field-Level Encryption (FLE) ensures that sensitive PII (Personally Identifiable Information)—such as national IDs, emails, and financial metrics—remains encrypted inside database buffers and tables.

Key Architecture: AES-256-GCM with Envelope Encryption

import { createCipheriv, createDecipheriv, randomBytes } from 'crypto';

interface EncryptedPayload {
  ciphertext: string; // Hex-encoded cipher text
  iv: string;         // Hex-encoded initialization vector
  tag: string;        // Hex-encoded authentication tag
  keyVersion: number; // Master key version for zero-downtime rotation
}

export class FieldEncryptionService {
  private masterKeys: Map<number, Buffer>;
  private activeVersion: number;

  constructor(keys: Record<number, string>, activeVersion: number) {
    this.masterKeys = new Map();
    for (const [v, hexKey] of Object.entries(keys)) {
      const keyBuf = Buffer.from(hexKey, 'hex');
      if (keyBuf.length !== 32) {
        throw new Error(`Key version ${v} must be exactly 256 bits (32 bytes).`);
      }
      this.masterKeys.set(Number(v), keyBuf);
    }
    this.activeVersion = activeVersion;
  }

  /**
   * Encrypts plaintext string using AES-256-GCM
   */
  public encrypt(plaintext: string): EncryptedPayload {
    const iv = randomBytes(12); // 96-bit IV for GCM
    const key = this.masterKeys.get(this.activeVersion);
    if (!key) throw new Error(`Active key version ${this.activeVersion} missing`);

    const cipher = createCipheriv('aes-256-gcm', key, iv);
    let ciphertext = cipher.update(plaintext, 'utf8', 'hex');
    ciphertext += cipher.final('hex');
    const tag = cipher.getAuthTag().toString('hex');

    return {
      ciphertext,
      iv: iv.toString('hex'),
      tag,
      keyVersion: this.activeVersion,
    };
  }

  /**
   * Decrypts payload and verifies authenticity tag
   */
  public decrypt(payload: EncryptedPayload): string {
    const key = this.masterKeys.get(payload.keyVersion);
    if (!key) throw new Error(`Key version ${payload.keyVersion} not configured for decryption`);

    const decipher = createDecipheriv(
      'aes-256-gcm',
      key,
      Buffer.from(payload.iv, 'hex')
    );
    decipher.setAuthTag(Buffer.from(payload.tag, 'hex'));

    let plaintext = decipher.update(payload.ciphertext, 'hex', 'utf8');
    plaintext += decipher.final('utf8');
    return plaintext;
  }
}

2. Enforcing TLS 1.3 in Transit

GDPR compliance requires eliminating deprecated cryptographic protocols (TLS 1.0, 1.1, and legacy cipher suites). All APIs and web applications must mandate TLS 1.3 or TLS 1.2 with Perfect Forward Secrecy (PFS).

NGINX Hardened TLS Configuration

server {
    listen 443 ssl http2;
    server_name api.yourdomain.com;

    # SSL Certificate Paths
    ssl_certificate /etc/letsencrypt/live/api.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/api.yourdomain.com/privkey.pem;

    # Enforce TLS 1.2 and 1.3 exclusively
    ssl_protocols TLSv1.2 TLSv1.3;

    # High-security AEAD cipher suites (PFS enabled)
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;

    # HSTS - Enforce HTTPS for 2 years including subdomains & preload
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "DENY" always;

    # SSL Session Caching
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:10m;
    ssl_session_tickets off;
}

3. Verification Checklist & Compliance Matrix

Requirement Implementation Target GDPR Article Mapping Verification Command
Field Encryption AES-256-GCM with 96-bit IV Article 32(1)(a) npm test cryptographic unit tests
TLS Protocol Minimum TLS 1.2 / Preferred TLS 1.3 Article 32(1)(a) npx testssl.sh api.yourdomain.com
Key Rotation Automated key version tag tracking Article 32(1)(d) Zero-downtime key rotation pipeline
Header Security HSTS max-age=63072000 Article 25 curl -I https://api.yourdomain.com

Conclusion & Next Steps

Implementing cryptographic protection at both the network tier (TLS 1.3) and the database field tier (AES-256-GCM) ensures that even in the event of an infrastructure breach, customer PII remains mathematically unreadable without authorization key access.