| name | data-encryption |
| description | Implement strong encryption using AES, RSA, TLS, and proper key management. Use when securing data at rest, in transit, or implementing end-to-end encryption. |
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;
2. 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()}")
3. 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();
4. 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