</>Học Dev
Bài học

Tuần 3 - Ngày 15: Encryption at Rest & in Transit

Tuần 3 – Ngày 15

Mục tiêu học tập

  • Phân biệt symmetric (AES-256-GCM) và asymmetric encryption (RSA, ECC) — khi nào dùng cái nào
  • Hiểu envelope encryption pattern: DEK + KEK, cách KMS hoạt động
  • So sánh AWS KMS, GCP KMS, Azure Key Vault — IAM-controlled key access
  • Biết database encryption at rest: TDE (Transparent Data Encryption) vs application-level
  • Hiểu E2EE (end-to-end encryption) ở mức cơ bản — Signal protocol intro
  • Tránh các sai lầm phổ biến: ECB mode, hardcoded keys, IV yếu, dùng RSA encrypt data lớn

1. Symmetric vs Asymmetric

SYMMETRICMtkeyduynhtchoencryptvàdecryptA[key]B(cùngkeyđencryptvàdecrypt)Nhanh(GB/giây),khósharekeyantoànquamngAlgorithm:AES,ChaCha20ASYMMETRICCp(public_key,private_key)A[pub_keyencrypt]B[priv_keydecrypt]plaintext(hocsignbngpriv_key,verifybngpub_key)Chm(KB/giâygp100-1000xln),public_keycóthsharecôngkhaiAlgorithm:RSA,ECC(Curve25519,P-256)

Trade-off và use case

Tiêu chíSymmetric (AES)Asymmetric (RSA/ECC)
Tốc độRất nhanhChậm
Key size128/256 bit2048-4096 bit (RSA), 256 bit (ECC)
Encrypt data lớnKHÔNG — chỉ encrypt key ngắn
Key distributionKhó (cần kênh an toàn)Dễ (public key share công khai)
Use case chínhBulk encryption (file, network)Key exchange, digital signature

Tại sao thực tế dùng cả hai (hybrid)?

TLS chính là ví dụ:

  • ECDHE (asymmetric, slow) chỉ để negotiate session key
  • AES-256-GCM (symmetric, fast) để encrypt dữ liệu chính

Asymmetric giải quyết vấn đề "làm sao share key an toàn", symmetric đảm nhận heavy lifting.


2. AES-GCM — AEAD chuẩn hiện đại

Block cipher mode

ECB(ElectronicCodeBook)KHÔNGBAOGIDÙNGblock_1encryptciphertext_1block_2encryptciphertext_2(gingblock_1ciphertextgingnhau)block_3encryptciphertext_3CBC(CipherBlockChaining)legacy,cóvnđpaddingoracleIVXORblock_1encryptc_1c_1XORblock_2encryptc_2...GCM(Galois/CounterMode)RECOMMENDEDcounter_0encryptXORblock_1=c_1counter_1encryptXORblock_2=c_2...+GMACtag(authentication)

Vì sao ECB là tai họa kinh điển

Image gốc (Tux):              Sau khi encrypt với AES-ECB:
████████████████              █▒█▓█▒▓█▒█▓█▒
█        ████                 ▒▓▒    ▓███
█        ████                 ▒▓▒    ▓███
█        ████                 ▒▓▒    ▓███
████████████████              █▒█▓█▒▓█▒█▓█▒

→ Pattern lộ rõ! Cùng plaintext block → cùng ciphertext block.

ECB là sai lầm cơ bản nhất trong cryptography. Mọi mode hiện đại (CBC, GCM, XTS) đều có IV (Initialization Vector) ngẫu nhiên để cùng plaintext cho ra ciphertext khác nhau.

AES-GCM trong Node.js

import { createCipheriv, createDecipheriv, randomBytes } from "node:crypto";

function encrypt(plaintext, key) {
  // KEY: 32 bytes (256 bit), bí mật
  // IV: 12 bytes (96 bit) ngẫu nhiên, KHÔNG được reuse với cùng key
  const iv = randomBytes(12);
  const cipher = createCipheriv("aes-256-gcm", key, iv);

  const encrypted = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
  const authTag = cipher.getAuthTag();  // 16 bytes

  // Lưu: iv + authTag + ciphertext (iv và tag KHÔNG cần bí mật)
  return Buffer.concat([iv, authTag, encrypted]);
}

function decrypt(data, key) {
  const iv = data.subarray(0, 12);
  const authTag = data.subarray(12, 28);
  const ciphertext = data.subarray(28);

  const decipher = createDecipheriv("aes-256-gcm", key, iv);
  decipher.setAuthTag(authTag);

  return Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString("utf8");
  // Nếu authTag mismatch → throw → biết data bị tamper
}

IV/Nonce rules

RULE: Với cùng một key, IV/nonce KHÔNG được reuse.
      Reuse IV trong GCM = catastrophic, attacker có thể recover key stream.

Cách sinh IV đúng:
1. Random 96-bit (cho GCM) — đủ entropy nếu < 2^32 message với cùng key
2. Counter (incremented mỗi message) — cần synchronization

Cách sinh IV SAI:
- Hardcoded "000000000000"
- Lấy từ timestamp với độ phân giải thấp
- Dùng IV cũ

3. Asymmetric: RSA và ECC

RSA

Key generation:
  - Chọn 2 prime lớn p, q
  - n = p * q  (modulus)
  - chọn e (public exponent, thường = 65537)
  - tính d (private exponent)
  - public_key = (n, e), private_key = (n, d)

Encrypt: c = m^e mod n
Decrypt: m = c^d mod n
  • Key size khuyến nghị: 3072 bit (~128-bit security). RSA-2048 vẫn được, sẽ deprecate dần.
  • Padding: BẮT BUỘC dùng OAEP (Optimal Asymmetric Encryption Padding). PKCS#1 v1.5 padding có lỗ hổng (Bleichenbacher attack).
  • Giới hạn: RSA-3072 chỉ encrypt được ≤ 384 bytes — 256 bytes sau khi trừ padding. Không bao giờ dùng RSA encrypt data thật, chỉ encrypt symmetric key.

ECC (Elliptic Curve Cryptography)

Curves phổ biến:
  - secp256r1 / P-256 / NIST P-256 (TLS, web standard)
  - secp384r1 / P-384
  - Curve25519 (Signal, modern, an toàn hơn NIST curves)
  - Curve448 (high security)
  • ECC-256 ≈ RSA-3072 về security level
  • Key nhỏ hơn rất nhiều → tốt cho mobile/IoT
  • Operation nhanh hơn RSA
  • Ed25519 cho signature, X25519 cho key exchange — đang là chuẩn mới

So sánh

RSA-3072ECDSA P-256Ed25519
Public key size384 bytes64 bytes32 bytes
Sign speedChậmTrung bìnhRất nhanh
Verify speedNhanhTrung bìnhRất nhanh
Security level~128-bit~128-bit~128-bit
RecommendedOKOKBest (cho new project)

4. Envelope Encryption — cách KMS hoạt động

Vấn đề trực tiếp dùng KMS

Nếu mỗi byte data đều gọi KMS encrypt:
- KMS có rate limit (~10,000 req/giây)
- Latency cao (mỗi gọi 10-50ms)
- Chi phí cao ($0.03/10,000 request)
- KMS không thiết kế để encrypt data lớn (giới hạn 4 KB)

Envelope encryption pattern

EnvelopeencryptionKEK(KeyEncryptionKey)KHÔNGBAOGIrikhiKMSnmtrongHardwareSecurityModule(HSM)DEK(DataEncryptionKey)AES-256,ephemeralciphertext_DEK=encrypt(KEK,DEK)lưucùngdataplaintextDEKchtntitrongmemoryappActualdata(cóthGB)ciphertext=AES-256-GCM(plaintext_DEK,data)

Flow encrypt

1. App gọi KMS GenerateDataKey(KeyId="my-kek", KeySpec=AES_256)
2. KMS trả về:
   - plaintext_DEK   (32 bytes — chỉ tồn tại trong memory app)
   - ciphertext_DEK  (DEK đã được encrypt bằng KEK trong KMS)
3. App encrypt data:
   encrypted_data = AES-256-GCM(plaintext_DEK, data)
4. App lưu xuống storage:
   { ciphertext_DEK, iv, authTag, encrypted_data }
5. App XÓA plaintext_DEK khỏi memory (zeroize)

Flow decrypt

1. App đọc { ciphertext_DEK, iv, authTag, encrypted_data } từ storage
2. App gọi KMS Decrypt(CiphertextBlob=ciphertext_DEK)
   → KMS verify IAM, decrypt bằng KEK, trả về plaintext_DEK
3. App decrypt data:
   data = AES-256-GCM-decrypt(plaintext_DEK, iv, authTag, encrypted_data)
4. App XÓA plaintext_DEK khỏi memory

Lợi ích

  • Performance: KMS chỉ gọi 1 lần / object (encrypt key 4 KB), không phải mỗi byte
  • Caching: có thể cache DEK in memory cho nhiều object trong session
  • Key rotation: rotate KEK trong KMS không cần re-encrypt data — chỉ cần re-encrypt DEK (nhanh)
  • Audit: KMS log mỗi Decrypt call → biết ai access data, khi nào

Code ví dụ (AWS KMS + Node.js)

import { KMSClient, GenerateDataKeyCommand, DecryptCommand } from "@aws-sdk/client-kms";
import { createCipheriv, createDecipheriv, randomBytes } from "node:crypto";

const kms = new KMSClient({ region: "ap-southeast-1" });
const KEY_ID = "alias/my-app-kek";

async function encryptObject(plaintext) {
  // Bước 1: Generate DEK
  const { Plaintext: dek, CiphertextBlob: encryptedDek } = await kms.send(
    new GenerateDataKeyCommand({ KeyId: KEY_ID, KeySpec: "AES_256" })
  );

  // Bước 2: Encrypt data bằng DEK
  const iv = randomBytes(12);
  const cipher = createCipheriv("aes-256-gcm", dek, iv);
  const ciphertext = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
  const authTag = cipher.getAuthTag();

  // Bước 3: Trả về envelope (DEK đã encrypt + ciphertext)
  return {
    encryptedDek: Buffer.from(encryptedDek).toString("base64"),
    iv: iv.toString("base64"),
    authTag: authTag.toString("base64"),
    ciphertext: ciphertext.toString("base64"),
  };
}

async function decryptObject(envelope) {
  // Bước 1: Decrypt DEK bằng KMS
  const { Plaintext: dek } = await kms.send(
    new DecryptCommand({
      CiphertextBlob: Buffer.from(envelope.encryptedDek, "base64"),
    })
  );

  // Bước 2: Decrypt data bằng DEK
  const decipher = createDecipheriv("aes-256-gcm", dek, Buffer.from(envelope.iv, "base64"));
  decipher.setAuthTag(Buffer.from(envelope.authTag, "base64"));
  return Buffer.concat([
    decipher.update(Buffer.from(envelope.ciphertext, "base64")),
    decipher.final(),
  ]).toString("utf8");
}

5. KMS so sánh: AWS, GCP, Azure

Tính chấtAWS KMSGCP Cloud KMSAzure Key Vault
AuthIAMGCP IAMAzure AD / Managed Identity
HSMFIPS 140-2 Level 2 (3 với HSM tier)FIPS 140-2 Level 3 (HSM keys)FIPS 140-2 Level 2 (Level 3 với Managed HSM)
BYOK (Bring Your Own Key)Có (import)
Hold Your Own Key (HYOK)XKS (External Key Store)EKM (External Key Manager)Managed HSM + customer key
Key rotationAuto (1 năm) cho symmetricAuto (configurable)Auto (configurable)
Cross-regionMulti-region keysMulti-region keyringGeo-replicated vault
Pricing$1/key/month + API calls$0.06/key version/month + API calls$0.03/10K transactions, premium tier có HSM

IAM-controlled key access

// AWS KMS key policy — ai được phép dùng key này
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowAppRoleToUseKey",
      "Effect": "Allow",
      "Principal": { "AWS": "arn:aws:iam::123456789012:role/app-role" },
      "Action": [
        "kms:Encrypt",
        "kms:Decrypt",
        "kms:GenerateDataKey",
        "kms:DescribeKey"
      ],
      "Resource": "*"
    },
    {
      "Sid": "DenyAuditorFromDecrypt",
      "Effect": "Deny",
      "Principal": { "AWS": "arn:aws:iam::123456789012:role/auditor" },
      "Action": "kms:Decrypt",
      "Resource": "*"
    }
  ]
}

Key policy + IAM policy đồng thời được evaluate. Mặc định KMS key chỉ trao quyền cho root account → phải explicit grant.


6. Database encryption at rest

Ba lớp encryption

Application-levelencryptionbnencrypttrongapptrưckhisaveDatabaseTDETransparentDataDBtencrypt,appkhôngbiếtEncryptionDisk/EBSvolumeFilesystem-level/diskencryption(full-diskencryption)

Bảng so sánh

LớpThreat protectedThreat KHÔNG protected
Full-disk (EBS encryption, LUKS)Disk bị stealDB connection compromise, SQL injection, admin xem data
TDE (DB-level)Backup steal, disk stealApp có access → đọc plaintext bình thường
Application-levelMọi threat trên + DBA xemApplication bug làm leak

TDE — Transparent Data Encryption

PostgreSQL: pgcrypto extension (column-level), hoặc dùng RDS encryption (full DB)
MySQL: native TDE từ 5.7+
SQL Server: TDE built-in (Enterprise edition)
Oracle: TDE built-in (Advanced Security option)

AWS RDS: tick "Enable encryption" khi tạo DB → toàn bộ storage, snapshot, replica đều encrypt
         Dùng AWS KMS key (default hoặc CMK của bạn)

TDE protection model:

Disk steal scenario:
   Attacker steal raw disk → đọc EBS snapshot → encrypted nonsense ✓ Safe

App compromise scenario:
   Attacker SQL injection → SELECT * FROM users → DB decrypt on the fly → plaintext ✗ Not safe

Application-level encryption (column-level)

-- Lưu thẳng encrypted blob vào column
CREATE TABLE users (
  id UUID PRIMARY KEY,
  email TEXT NOT NULL,
  ssn_encrypted BYTEA,           -- AES-256-GCM ciphertext
  ssn_encrypted_dek BYTEA        -- DEK encrypted by KMS
);
// App encrypt trước khi INSERT
const { encryptedDek, iv, authTag, ciphertext } = await encryptObject(user.ssn);
await db.query(
  "INSERT INTO users (id, email, ssn_encrypted, ssn_encrypted_dek) VALUES ($1, $2, $3, $4)",
  [user.id, user.email, Buffer.concat([iv, authTag, ciphertext]), encryptedDek]
);

// Decrypt khi cần dùng — DBA query thẳng DB chỉ thấy ciphertext

Trade-off:

  • Pros: DBA và backup compromise không lộ data
  • Cons: query/index trên encrypted field rất khó, latency cao hơn, complexity tăng

Đặc biệt: searchable encryption / deterministic encryption

Nếu cần WHERE email = ? trên encrypted column, có thể dùng deterministic encryption (cùng plaintext → cùng ciphertext). Nhưng deterministic mode lộ pattern (như ECB ở mức row) — chỉ dùng cho lookup, không cho data nhạy cảm chính.


7. End-to-End Encryption (E2EE)

Khái niệm

Server-sideencryption(Gmail,Dropbox):ClientTLSServer(decrypt)re-encryptatrestStorageServercókhnăngđcplaintextbtclúcnàoE2EE(Signal,WhatsApp,iMessage):ClientAencryptsClientBdecryptsServerchchuynciphertext,khôngdecryptđưc

Signal Protocol — chuẩn de facto

Concepts:
- Double Ratchet: mỗi message dùng key khác, key forward-secret
- X3DH (Extended Triple Diffie-Hellman): key agreement async
- Pre-keys: cho phép initiate session khi recipient offline

Properties đạt được:
- Forward secrecy: leak key hiện tại không decrypt được message cũ
- Future secrecy (post-compromise security): leak key tạm → tự healing sau vài turn
- Deniability: không thể prove ai gửi message cụ thể nào

E2EE trong app phổ biến

AppE2EE defaultGroup chatBackup E2EE
SignalCó (PIN-encrypted)
WhatsAppCó (optional, từ 2021)
iMessageCó (Advanced Data Protection, opt-in)
TelegramKHÔNG (chỉ Secret Chat)KHÔNGKHÔNG
SlackKHÔNG--
ZoomCó (opt-in từ 2020)Limited-

Khi nào dev cần biết E2EE?

  • Build app messaging / collaboration nhạy cảm
  • Build storage app cho user (Standard Notes, Bitwarden, ProtonMail)
  • Healthcare, legal — compliance yêu cầu provider không đọc được content

Library: libsignal, Matrix/Olm, Tink.


8. Sai lầm crypto phổ biến

1. Dùng ECB mode

# ❌ NGUY HIỂM
from Crypto.Cipher import AES
cipher = AES.new(key, AES.MODE_ECB)
ciphertext = cipher.encrypt(pad(plaintext, 16))

# ✅ ĐÚNG
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
nonce = get_random_bytes(12)
cipher = AES.new(key, AES.MODE_GCM, nonce=nonce)
ciphertext, tag = cipher.encrypt_and_digest(plaintext)

2. Hardcode key trong source

// ❌ NGUY HIỂM
const KEY = Buffer.from("0123456789abcdef0123456789abcdef", "hex");

// ✅ ĐÚNG — load từ KMS/secret manager
const key = await loadKeyFromKMS();

3. IV/Nonce reuse

// ❌ NGUY HIỂM — cùng IV cho mọi message
const IV = Buffer.alloc(12, 0);
const cipher = createCipheriv("aes-256-gcm", key, IV);

// ✅ ĐÚNG
const iv = randomBytes(12);  // random mỗi lần

4. Dùng RSA encrypt data thật

# ❌ NGUY HIỂM (chỉ encrypt được vài trăm byte)
from cryptography.hazmat.primitives.asymmetric import padding
ciphertext = public_key.encrypt(huge_data, padding.OAEP(...))

# ✅ ĐÚNG — hybrid encryption
# 1. Generate random AES key
# 2. Encrypt data bằng AES-GCM
# 3. Encrypt AES key bằng RSA-OAEP

5. Roll your own crypto

Quy tắc: KHÔNG TỰ VIẾT crypto primitive.
Dùng library đã được audit: libsodium, Tink, OpenSSL, BoringSSL, ring (Rust).

6. MD5/SHA-1 cho password hashing

// ❌ NGUY HIỂM — MD5/SHA-1 broken, không slow, không salted
const hash = createHash("md5").update(password).digest("hex");

// ✅ ĐÚNG — password hash chuyên dụng
import { hash, verify } from "@node-rs/argon2";
const hashed = await hash(password);          // argon2id, salt tự động
const ok = await verify(hashed, password);
// Hoặc bcrypt, scrypt, PBKDF2

7. Weak random (Math.random, time)

// ❌ NGUY HIỂM — Math.random predictable
const token = Math.random().toString(36);

// ✅ ĐÚNG
import { randomBytes } from "node:crypto";
const token = randomBytes(32).toString("hex");

8. So sánh hash/MAC bằng ==

// ❌ NGUY HIỂM — timing attack
if (computedHmac === providedHmac) { ... }

// ✅ ĐÚNG — constant-time compare
import { timingSafeEqual } from "node:crypto";
if (timingSafeEqual(Buffer.from(computedHmac), Buffer.from(providedHmac))) { ... }

9. Câu hỏi ôn tập

  1. Vì sao thực tế dùng hybrid encryption (asymmetric + symmetric) thay vì chỉ một loại?

    Xem đáp án

    Symmetric (AES) nhanh, encrypt được data lớn (GB/s), nhưng có vấn đề key distribution — làm sao share key bí mật qua kênh không an toàn? Asymmetric (RSA, ECC) giải quyết key distribution (public key có thể public), nhưng cực chậm và chỉ encrypt được data nhỏ (vài trăm byte).

    Hybrid pattern: dùng asymmetric chỉ để trao đổi/encrypt một symmetric key ngắn, sau đó dùng symmetric key đó encrypt data lớn. TLS, PGP, S/MIME, age tool đều dùng pattern này. Envelope encryption (KMS) cũng là một biến thể: KEK trong HSM "asymmetric-like" còn DEK là symmetric.

  2. Trong envelope encryption với AWS KMS, vì sao thiết kế này hiệu quả hơn việc gọi kms:Encrypt trực tiếp lên data?

    Xem đáp án

    (1) Performance: KMS có giới hạn 4 KB/request và rate limit ~10K req/s. Encrypt object 100 MB trực tiếp không khả thi. Với envelope, KMS chỉ gọi 1 lần để encrypt/decrypt DEK (32 bytes), bulk encryption làm bằng AES local.

    (2) Cost: KMS request có phí ($0.03/10K), envelope giảm số request KMS đáng kể.

    (3) Key rotation: rotate KEK trong KMS chỉ cần re-encrypt các DEK (nhanh), không cần đụng data. Rotate trực tiếp = phải đọc, decrypt, re-encrypt mọi byte data.

    (4) Audit: KMS log mỗi Decrypt → trace được ai access data, khi nào.

  3. Sự khác biệt giữa TDE và application-level encryption — và threat nào bảo vệ được/không?

    Xem đáp án

    TDE (Transparent Data Encryption): DB tự encrypt khi ghi disk, decrypt khi đọc — app không biết. Protect được: disk/snapshot/backup bị steal. KHÔNG protect: app/DBA query thẳng DB sẽ thấy plaintext (DB decrypt on-the-fly).

    Application-level: app encrypt data trước khi INSERT, decrypt sau khi SELECT. Protect: cả DBA và compromised backup đều chỉ thấy ciphertext. Trade-off: query/index trên encrypted field rất khó, latency cao hơn.

    Quy tắc thường dùng: TDE cho mọi DB (default), application-level thêm cho các column siêu nhạy cảm (SSN, credit card, health record).

  4. Tại sao dùng AES-ECB là sai lầm cơ bản, và chế độ nào nên dùng?

    Xem đáp án

    ECB encrypt mỗi block độc lập, cùng plaintext block → cùng ciphertext block. Hệ quả: pattern trong plaintext (ví dụ vùng pixel màu giống nhau trong ảnh, header lặp lại) lộ ra trong ciphertext. Hình "ECB-encrypted Tux" là minh hoạ kinh điển — vẫn nhận ra hình con chim cánh cụt sau khi "encrypt".

    Nên dùng: AES-GCM (AEAD — authenticated encryption với associated data) hoặc ChaCha20-Poly1305 cho mobile. Cả hai có IV/nonce ngẫu nhiên (cùng plaintext → ciphertext khác nhau) và có MAC tag chống tampering. Tránh CBC mode (legacy, dễ bị padding oracle attack nếu implement sai).

  5. Vì sao E2EE khác với "encryption at rest + TLS in transit" mà các SaaS thường quảng cáo là "encrypted"?

    Xem đáp án

    Với encryption at rest + TLS:

    • TLS bảo vệ data trên đường truyền giữa client và server
    • At-rest encryption bảo vệ data trên disk của server
    • Nhưng: server vẫn decrypt data trong memory để xử lý → server có khả năng đọc plaintext bất cứ lúc nào. Nhân viên service provider, government subpoena, hoặc attacker chiếm server đều có thể đọc.

    E2EE: data được encrypt tại client (ví dụ Signal app trên điện thoại A), chỉ decrypt tại client nhận (điện thoại B). Server chỉ relay ciphertext, không có khả năng decrypt — kể cả Signal/WhatsApp staff cũng không đọc được.

    Trade-off của E2EE: server-side search/preview/spam filtering khó hơn nhiều, password recovery thường yêu cầu device cũ (vì server không có key).

Bài tập thực hành

# 1. AES-GCM encrypt/decrypt với openssl
echo "Hello secret" | openssl enc -aes-256-gcm -e \
  -K $(openssl rand -hex 32) \
  -iv $(openssl rand -hex 12) \
  -base64

# 2. Generate RSA và ECDSA key pair
openssl genrsa -out rsa-private.pem 3072
openssl rsa -in rsa-private.pem -pubout -out rsa-public.pem

openssl ecparam -name secp256r1 -genkey -noout -out ec-private.pem
openssl ec -in ec-private.pem -pubout -out ec-public.pem

# 3. Encrypt file bằng hybrid (RSA + AES)
openssl rand -out aes.key 32
openssl rand -out aes.iv 16

# Encrypt data
openssl enc -aes-256-cbc -in document.txt -out document.enc \
  -K $(xxd -p aes.key | tr -d '\n') \
  -iv $(xxd -p aes.iv | tr -d '\n')

# Encrypt AES key bằng RSA
openssl pkeyutl -encrypt -inkey rsa-public.pem -pubin \
  -in aes.key -out aes.key.enc

# 4. Demo AWS KMS envelope encryption với CLI
aws kms create-key --description "demo-kek"
KEY_ID=<from output>

# Generate DEK
aws kms generate-data-key --key-id $KEY_ID --key-spec AES_256
# → Plaintext (base64 32 bytes), CiphertextBlob (encrypted DEK)

# 5. Demo password hashing đúng cách
npm install argon2
node -e "
const argon2 = require('argon2');
(async () => {
  const hash = await argon2.hash('mypassword', { type: argon2.argon2id });
  console.log('Hash:', hash);
  console.log('Verify:', await argon2.verify(hash, 'mypassword'));
})();
"

# 6. Check RDS encryption status
aws rds describe-db-instances --query \
  'DBInstances[*].[DBInstanceIdentifier,StorageEncrypted,KmsKeyId]'

Tài liệu tham khảo chính thức


Tiếp theo: Ngày 16 — Supply Chain Attacks