Data Encryption Overview
Implement robust encryption strategies for protecting sensitive data at rest and in transit using industry-standard cryptographic algorithms and key management practices.
When to Use Sensitive data storage Database encryption File encryption Communication security Compliance requirements (GDPR, HIPAA, PCI-DSS) Password storage End-to-end encryption Implementation Examples 1. Node.js Encryption Library // encryption-service.js const crypto = require('crypto'); const fs = require('fs').promises;
class EncryptionService { constructor() { // AES-256-GCM for symmetric encryption this.algorithm = 'aes-256-gcm'; this.keyLength = 32; // 256 bits this.ivLength = 16; // 128 bits this.saltLength = 64; this.tagLength = 16; }
/* * Generate a cryptographically secure random key / generateKey() { return crypto.randomBytes(this.keyLength); }
/* * Derive a key from a password using PBKDF2 / async deriveKey(password, salt = null) { if (!salt) { salt = crypto.randomBytes(this.saltLength); }
return new Promise((resolve, reject) => {
crypto.pbkdf2(
password,
salt,
100000, // iterations
this.keyLength,
'sha512',
(err, derivedKey) => {
if (err) reject(err);
else resolve({ key: derivedKey, salt });
}
);
});
}
/* * Encrypt data using AES-256-GCM / encrypt(data, key) { const iv = crypto.randomBytes(this.ivLength); const cipher = crypto.createCipheriv(this.algorithm, key, iv);
let encrypted = cipher.update(data, 'utf8', 'hex');
encrypted += cipher.final('hex');
const tag = cipher.getAuthTag();
// Return IV + encrypted data + auth tag
return {
encrypted: encrypted,
iv: iv.toString('hex'),
tag: tag.toString('hex')
};
}
/* * Decrypt data using AES-256-GCM / decrypt(encryptedData, key, iv, tag) { const decipher = crypto.createDecipheriv( this.algorithm, key, Buffer.from(iv, 'hex') );
decipher.setAuthTag(Buffer.from(tag, 'hex'));
let decrypted = decipher.update(encryptedData, 'hex', 'utf8');
decrypted += decipher.final('utf8');
return decrypted;
}
/* * Encrypt file / async encryptFile(inputPath, outputPath, key) { const iv = crypto.randomBytes(this.ivLength); const cipher = crypto.createCipheriv(this.algorithm, key, iv);
const input = await fs.readFile(inputPath);
const encrypted = Buffer.concat([
cipher.update(input),
cipher.final()
]);
const tag = cipher.getAuthTag();
// Write IV + encrypted data + auth tag
const output = Buffer.concat([iv, encrypted, tag]);
await fs.writeFile(outputPath, output);
return { iv: iv.toString('hex'), tag: tag.toString('hex') };
}
/* * Decrypt file / async decryptFile(inputPath, outputPath, key) { const data = await fs.readFile(inputPath);
const iv = data.subarray(0, this.ivLength);
const tag = data.subarray(data.length - this.tagLength);
const encrypted = data.subarray(this.ivLength, data.length - this.tagLength);
const decipher = crypto.createDecipheriv(this.algorithm, key, iv);
decipher.setAuthTag(tag);
const decrypted = Buffer.concat([
decipher.update(encrypted),
decipher.final()
]);
await fs.writeFile(outputPath, decrypted);
}
/* * Hash password using bcrypt-style approach / async hashPassword(password) { const salt = crypto.randomBytes(16);
return new Promise((resolve, reject) => {
crypto.pbkdf2(
password,
salt,
100000,
64,
'sha512',
(err, hash) => {
if (err) reject(err);
else {
const combined = Buffer.concat([salt, hash]);
resolve(combined.toString('hex'));
}
}
);
});
}
/* * Verify password hash / async verifyPassword(password, hashedPassword) { const combined = Buffer.from(hashedPassword, 'hex'); const salt = combined.subarray(0, 16); const hash = combined.subarray(16);
return new Promise((resolve, reject) => {
crypto.pbkdf2(
password,
salt,
100000,
64,
'sha512',
(err, derivedHash) => {
if (err) reject(err);
else resolve(crypto.timingSafeEqual(hash, derivedHash));
}
);
});
}
/* * Generate RSA key pair / generateKeyPair() { return crypto.generateKeyPairSync('rsa', { modulusLength: 4096, publicKeyEncoding: { type: 'spki', format: 'pem' }, privateKeyEncoding: { type: 'pkcs8', format: 'pem', cipher: 'aes-256-cbc', passphrase: process.env.KEY_PASSPHRASE || 'top-secret' } }); }
/* * Encrypt with public key (RSA) / encryptWithPublicKey(data, publicKey) { return crypto.publicEncrypt( { key: publicKey, padding: crypto.constants.RSA_PKCS1_OAEP_PADDING, oaepHash: 'sha256' }, Buffer.from(data) ); }
/* * Decrypt with private key (RSA) / decryptWithPrivateKey(encrypted, privateKey) { return crypto.privateDecrypt( { key: privateKey, padding: crypto.constants.RSA_PKCS1_OAEP_PADDING, oaepHash: 'sha256' }, encrypted ); } }
// Usage examples async function main() { const encryptionService = new EncryptionService();
// 1. Symmetric encryption const key = encryptionService.generateKey(); const encrypted = encryptionService.encrypt('Secret message', key); console.log('Encrypted:', encrypted);
const decrypted = encryptionService.decrypt( encrypted.encrypted, key, encrypted.iv, encrypted.tag ); console.log('Decrypted:', decrypted);
// 2. Password-based encryption const { key: derivedKey, salt } = await encryptionService.deriveKey('myPassword'); const passwordEncrypted = encryptionService.encrypt('Data', derivedKey); console.log('Password encrypted:', passwordEncrypted);
// 3. Password hashing const hashedPassword = await encryptionService.hashPassword('userPassword123'); const isValid = await encryptionService.verifyPassword('userPassword123', hashedPassword); console.log('Password valid:', isValid);
// 4. RSA encryption const { publicKey, privateKey } = encryptionService.generateKeyPair(); const rsaEncrypted = encryptionService.encryptWithPublicKey('Secret', publicKey); const rsaDecrypted = encryptionService.decryptWithPrivateKey(rsaEncrypted, privateKey); console.log('RSA decrypted:', rsaDecrypted.toString()); }
main().catch(console.error);
module.exports = EncryptionService;
- Python Cryptography Implementation
encryption_service.py
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2 from cryptography.hazmat.primitives.asymmetric import rsa, padding from cryptography.hazmat.backends import default_backend import os import base64 from typing import Tuple, Dict
class EncryptionService: def init(self): self.backend = default_backend()
def generate_key(self) -> bytes:
"""Generate a random 256-bit key"""
return os.urandom(32)
def derive_key(self, password: str, salt: bytes = None) -> Tuple[bytes, bytes]:
"""Derive encryption key from password using PBKDF2"""
if salt is None:
salt = os.urandom(16)
kdf = PBKDF2(
algorithm=hashes.SHA256(),
length=32,
salt=salt,
iterations=100000,
backend=self.backend
)
key = kdf.derive(password.encode())
return key, salt
def encrypt_aes_gcm(self, plaintext: bytes, key: bytes) -> Dict[str, str]:
"""Encrypt data using AES-256-GCM"""
iv = os.urandom(12) # 96-bit IV for GCM
cipher = Cipher(
algorithms.AES(key),
modes.GCM(iv),
backend=self.backend
)
encryptor = cipher.encryptor()
ciphertext = encryptor.update(plaintext) + encryptor.finalize()
return {
'ciphertext': base64.b64encode(ciphertext).decode(),
'iv': base64.b64encode(iv).decode(),
'tag': base64.b64encode(encryptor.tag).decode()
}
def decrypt_aes_gcm(self, ciphertext: str, key: bytes, iv: str, tag: str) -> bytes:
"""Decrypt data using AES-256-GCM"""
cipher = Cipher(
algorithms.AES(key),
modes.GCM(
base64.b64decode(iv),
base64.b64decode(tag)
),
backend=self.backend
)
decryptor = cipher.decryptor()
plaintext = decryptor.update(base64.b64decode(ciphertext)) + decryptor.finalize()
return plaintext
def encrypt_file(self, input_path: str, output_path: str, key: bytes) -> None:
"""Encrypt file using AES-256-GCM"""
with open(input_path, 'rb') as f:
plaintext = f.read()
result = self.encrypt_aes_gcm(plaintext, key)
# Write IV + ciphertext + tag
with open(output_path, 'wb') as f:
f.write(base64.b64decode(result['iv']))
f.write(base64.b64decode(result['ciphertext']))
f.write(base64.b64decode(result['tag']))
def decrypt_file(self, input_path: str, output_path: str, key: bytes) -> None:
"""Decrypt file using AES-256-GCM"""
with open(input_path, 'rb') as f:
data = f.read()
iv = data[:12]
tag = data[-16:]
ciphertext = data[12:-16]
cipher = Cipher(
algorithms.AES(key),
modes.GCM(iv, tag),
backend=self.backend
)
decryptor = cipher.decryptor()
plaintext = decryptor.update(ciphertext) + decryptor.finalize()
with open(output_path, 'wb') as f:
f.write(plaintext)
def generate_rsa_keypair(self) -> Tuple[bytes, bytes]:
"""Generate RSA key pair"""
private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=4096,
backend=self.backend
)
private_pem = private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.BestAvailableEncryption(b'passphrase')
)
public_pem = private_key.public_key().public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo
)
return private_pem, public_pem
def encrypt_rsa(self, plaintext: bytes, public_key_pem: bytes) -> bytes:
"""Encrypt with RSA public key"""
public_key = serialization.load_pem_public_key(
public_key_pem,
backend=self.backend
)
ciphertext = public_key.encrypt(
plaintext,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
return ciphertext
def decrypt_rsa(self, ciphertext: bytes, private_key_pem: bytes, passphrase: bytes) -> bytes:
"""Decrypt with RSA private key"""
private_key = serialization.load_pem_private_key(
private_key_pem,
password=passphrase,
backend=self.backend
)
plaintext = private_key.decrypt(
ciphertext,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
return plaintext
Usage
if name == 'main': service = EncryptionService()
# AES encryption
key = service.generate_key()
encrypted = service.encrypt_aes_gcm(b'Secret data', key)
print(f"Encrypted: {encrypted['ciphertext']}")
decrypted = service.decrypt_aes_gcm(
encrypted['ciphertext'],
key,
encrypted['iv'],
encrypted['tag']
)
print(f"Decrypted: {decrypted.decode()}")
# Password-based encryption
password = "mySecurePassword"
key, salt = service.derive_key(password)
print(f"Derived key: {base64.b64encode(key).decode()}")
# RSA encryption
private_key, public_key = service.generate_rsa_keypair()
rsa_encrypted = service.encrypt_rsa(b'Secret message', public_key)
rsa_decrypted = service.decrypt_rsa(rsa_encrypted, private_key, b'passphrase')
print(f"RSA decrypted: {rsa_decrypted.decode()}")
- Database Encryption (PostgreSQL) -- Database-level encryption using pgcrypto
-- Enable pgcrypto extension CREATE EXTENSION IF NOT EXISTS pgcrypto;
-- Create table with encrypted columns CREATE TABLE users ( id SERIAL PRIMARY KEY, email VARCHAR(255) NOT NULL, -- Encrypted sensitive data ssn BYTEA, credit_card BYTEA, created_at TIMESTAMP DEFAULT NOW() );
-- Insert encrypted data INSERT INTO users (email, ssn, credit_card) VALUES ( 'user@example.com', pgp_sym_encrypt('123-45-6789', 'encryption-key'), pgp_sym_encrypt('4111-1111-1111-1111', 'encryption-key') );
-- Query encrypted data SELECT email, pgp_sym_decrypt(ssn, 'encryption-key') AS ssn, pgp_sym_decrypt(credit_card, 'encryption-key') AS credit_card FROM users WHERE email = 'user@example.com';
-- Create function for transparent encryption CREATE OR REPLACE FUNCTION encrypt_sensitive_data() RETURNS TRIGGER AS $$ BEGIN IF NEW.ssn IS NOT NULL THEN NEW.ssn := pgp_sym_encrypt(NEW.ssn::TEXT, current_setting('app.encryption_key')); END IF;
IF NEW.credit_card IS NOT NULL THEN
NEW.credit_card := pgp_sym_encrypt(NEW.credit_card::TEXT, current_setting('app.encryption_key'));
END IF;
RETURN NEW;
END; $$ LANGUAGE plpgsql;
-- Attach trigger CREATE TRIGGER encrypt_before_insert BEFORE INSERT ON users FOR EACH ROW EXECUTE FUNCTION encrypt_sensitive_data();
- TLS/SSL Configuration // tls-server.js - HTTPS server with strong TLS const https = require('https'); const fs = require('fs');
const tlsOptions = { key: fs.readFileSync('private-key.pem'), cert: fs.readFileSync('certificate.pem'), ca: fs.readFileSync('ca-cert.pem'), // Certificate authority
// TLS version restrictions minVersion: 'TLSv1.2', maxVersion: 'TLSv1.3',
// Strong cipher suites ciphers: [ 'TLS_AES_256_GCM_SHA384', 'TLS_CHACHA20_POLY1305_SHA256', 'TLS_AES_128_GCM_SHA256', 'ECDHE-RSA-AES256-GCM-SHA384', 'ECDHE-RSA-AES128-GCM-SHA256' ].join(':'),
// Prefer server cipher order honorCipherOrder: true,
// Require client certificate (mutual TLS) requestCert: true, rejectUnauthorized: true };
const server = https.createServer(tlsOptions, (req, res) => { // Verify client certificate const cert = req.socket.getPeerCertificate();
if (req.client.authorized) { res.writeHead(200); res.end('Secure connection established'); } else { res.writeHead(401); res.end('Unauthorized'); } });
server.listen(443, () => { console.log('Secure server running on port 443'); });
Best Practices ✅ DO Use AES-256-GCM for symmetric encryption Use RSA-4096 or ECC for asymmetric encryption Implement proper key rotation Use secure key storage (HSM, KMS) Salt and hash passwords Use TLS 1.2+ for transit encryption Implement key derivation (PBKDF2, Argon2) Use authenticated encryption ❌ DON'T Roll your own crypto Store keys in code Use ECB mode Use MD5 or SHA1 Reuse IVs/nonces Use weak key lengths Skip authentication tags Encryption Standards AES-256: Symmetric encryption RSA-4096: Asymmetric encryption ECDSA/EdDSA: Digital signatures TLS 1.3: Transport security PBKDF2/Argon2: Key derivation HMAC-SHA256: Message authentication Resources NIST Cryptographic Standards OWASP Cryptographic Storage Cheat Sheet Node.js Crypto Documentation Python Cryptography Library