Mã hóa chuyển đổi dữ liệu có thể đọc được (văn bản gốc) thành dữ liệu không thể đọc được (văn bản mã hóa) và chỉ có thể đảo ngược được bằng khóa chính xác. Đây là công cụ chính để bảo vệ tính bảo mật của dữ liệu—đảm bảo rằng ngay cả khi dữ liệu bị chặn hoặc bị đánh cắp, dữ liệu đó vẫn vô dụng đối với những kẻ tấn công.
Có hai loại mã hóa cơ bản: Đối xứng (một khóa cho cả mã hóa và giải mã) và aĐối xứng (các khóa riêng biệt để mã hóa và giải mã). Mỗi loại đều có trường hợp sử dụng riêng biệt và hiểu được thời điểm sử dụng, điều này rất quan trọng đối với thiết kế hệ thống an toàn.
Mã hóa đối xứng
Mã hóa đối xứng sử dụng cùng một khóa cho cả mã hóa và giải mã. Nó nhanh chóng và hiệu quả, lý tưởng cho việc mã hóa lượng lớn dữ liệu.
Nó hoạt động như thế nào
Plaintext + Key → [Encryption Algorithm] → Ciphertext
Ciphertext + Key → [Decryption Algorithm] → Plaintext
Tính bảo mật phụ thuộc hoàn toàn vào việc giữ bí mật khóa. Nếu kẻ tấn công lấy được khóa, chúng có thể giải mã tất cả dữ liệu được mã hóa bằng khóa đó.
Các thuật toán đối xứng phổ biến
| Thuật toán | Kích thước phím | Trạng thái | Trường hợp sử dụng |
|---|---|---|---|
| AES-256 | 256 bit | ✅ Được đề xuất | Mục đích chung, tiêu chuẩn chính phủ |
| AES-128 | 128 bit | ✅ An toàn | Nhanh hơn AES-256, vẫn rất an toàn |
| ChaCha20 | 256 bit | ✅ Được đề xuất | Triển khai phần mềm/di động/nhúng |
| 3DES | 168 bit | ⚠️ Không dùng nữa | Chỉ các hệ thống cũ |
| DES | 56 bit | ❌ Hỏng | Không bao giờ sử dụng |
| RC4 | Biến | ❌ Hỏng | Không bao giờ sử dụng |
AES (Tiêu chuẩn mã hóa nâng cao)
AES là tiêu chuẩn vàng cho mã hóa đối xứng. Được NIST áp dụng vào năm 2001, nó được sử dụng ở mọi nơi—từ HTTPS đến mã hóa ổ đĩa cho đến lưu trữ đám mây.
from cryptography.fernet import Fernet
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
import os
# High-level API (recommended for most use cases)
def encrypt_with_fernet(plaintext: bytes) -> tuple[bytes, bytes]:
"""Encrypt data using Fernet (AES-128-CBC + HMAC)."""
key = Fernet.generate_key()
f = Fernet(key)
ciphertext = f.encrypt(plaintext)
return ciphertext, key
def decrypt_with_fernet(ciphertext: bytes, key: bytes) -> bytes:
"""Decrypt Fernet-encrypted data."""
f = Fernet(key)
return f.decrypt(ciphertext)
# Example usage
message = b"Sensitive configuration data"
encrypted, key = encrypt_with_fernet(message)
decrypted = decrypt_with_fernet(encrypted, key)
assert decrypted == message
Chặn chế độ mật mã
AES là mật mã khối—nó mã hóa các khối có kích thước cố định (128 bit). Để mã hóa dữ liệu lớn hơn một khối, bạn cần có chế độ hoạt động ****:
| Chế độ | Mô tả | Trường hợp sử dụng |
|---|---|---|
| GCM | Chế độ Galois/Bộ đếm | ✅ Khuyến nghị - mã hóa được xác thực |
| CBC | Chuỗi khối mật mã | Phổ biến nhưng yêu cầu MAC riêng |
| CTR | Chế độ đếm | Có thể song song hóa, cần MAC |
| ECB | Sách mã điện tử | ❌ Không bao giờ sử dụng - tiết lộ các mẫu |
Luôn sử dụng mã hóa xác thực (như GCM) để cung cấp cả tính bảo mật và tính toàn vẹn:
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import os
def encrypt_aes_gcm(plaintext: bytes, associated_data: bytes = b"") -> tuple[bytes, bytes, bytes]:
"""
Encrypt using AES-256-GCM (authenticated encryption).
Returns: (ciphertext, key, nonce)
"""
key = AESGCM.generate_key(bit_length=256)
aesgcm = AESGCM(key)
# Nonce must be unique for each encryption with the same key
# 96 bits (12 bytes) is recommended for GCM
nonce = os.urandom(12)
# Associated data is authenticated but not encrypted
ciphertext = aesgcm.encrypt(nonce, plaintext, associated_data)
return ciphertext, key, nonce
def decrypt_aes_gcm(ciphertext: bytes, key: bytes, nonce: bytes,
associated_data: bytes = b"") -> bytes:
"""Decrypt AES-256-GCM ciphertext."""
aesgcm = AESGCM(key)
return aesgcm.decrypt(nonce, ciphertext, associated_data)
Vấn đề của ECB
Chế độ ECB mã hóa từng khối một cách độc lập, hiển thị các mẫu trong bản rõ:
Original Image: ECB Encrypted: CBC/GCM Encrypted:
███░░░███ ▓▓▓░░░▓▓▓ ▒█░▓▒█░▓▒
█████████ ▓▓▓▓▓▓▓▓▓ ░▓█▒░▓█▒░
███░░░███ ▓▓▓░░░▓▓▓ ▓░▒█▓░▒█▓
(Pattern visible) (Pattern visible) (Random - secure)
Đây là lý do tại sao ** không bao giờ nên sử dụng ECB** cho dữ liệu thực.
Mã hóa bất đối xứng
Mã hóa bất đối xứng sử dụng cặp khóa ****: khóa chung (được chia sẻ công khai) và khóa riêng (được giữ bí mật). Dữ liệu được mã hóa bằng khóa chung chỉ có thể được giải mã bằng khóa riêng và ngược lại.
Nó hoạt động như thế nào
Encryption: Plaintext + Public Key → Ciphertext
Decryption: Ciphertext + Private Key → Plaintext
Signing: Message + Private Key → Signature
Verification: Message + Signature + Public Key → Valid/Invalid
Điều này giải quyết vấn đề phân phối khóa ****—bạn có thể chia sẻ khóa chung của mình với bất kỳ ai mà không ảnh hưởng đến bảo mật.
Các thuật toán bất đối xứng phổ biến
| Thuật toán | Kích thước phím | Trạng thái | Trường hợp sử dụng |
|---|---|---|---|
| RSA | Hơn 2048 bit | ✅ An toàn | Mã hóa, chữ ký, trao đổi khóa |
| ECDSA | Hơn 256 bit | ✅ Được đề xuất | Chữ ký số (nhỏ hơn, nhanh hơn) |
| Ed25519 | 256 bit | ✅ Được đề xuất | Chữ ký (hiện đại, nhanh chóng) |
| ECDH | Hơn 256 bit | ✅ Được đề xuất | Trao đổi khóa |
| DSA | Hơn 2048 bit | ⚠️ Không dùng nữa | Chỉ chữ ký kế thừa |
Ví dụ về RSA
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import hashes, serialization
def generate_rsa_keypair():
"""Generate a 2048-bit RSA key pair."""
private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048,
)
public_key = private_key.public_key()
return private_key, public_key
def rsa_encrypt(plaintext: bytes, public_key) -> bytes:
"""Encrypt data with RSA public key."""
return public_key.encrypt(
plaintext,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
def rsa_decrypt(ciphertext: bytes, private_key) -> bytes:
"""Decrypt data with RSA private key."""
return private_key.decrypt(
ciphertext,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
# Example usage
private_key, public_key = generate_rsa_keypair()
message = b"Secret message for recipient"
encrypted = rsa_encrypt(message, public_key)
decrypted = rsa_decrypt(encrypted, private_key)
assert decrypted == message
Chữ ký số với Ed25519
Ed25519 là thuật toán chữ ký hiện đại nhanh hơn và an toàn hơn chữ ký RSA:
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
def generate_signing_keypair():
"""Generate Ed25519 signing key pair."""
private_key = Ed25519PrivateKey.generate()
public_key = private_key.public_key()
return private_key, public_key
def sign_message(message: bytes, private_key) -> bytes:
"""Sign a message with Ed25519 private key."""
return private_key.sign(message)
def verify_signature(message: bytes, signature: bytes, public_key) -> bool:
"""Verify an Ed25519 signature."""
try:
public_key.verify(signature, message)
return True
except Exception:
return False
# Example: Signing a container image digest
private_key, public_key = generate_signing_keypair()
image_digest = b"sha256:abc123def456..."
signature = sign_message(image_digest, private_key)
# Anyone with the public key can verify
is_valid = verify_signature(image_digest, signature, public_key)
print(f"Signature valid: {is_valid}") # True
Đối xứng và bất đối xứng: Khi nào nên sử dụng cái nào
| Khía cạnh | đối xứng | Bất đối xứng |
|---|---|---|
| Tốc độ | Nhanh (1000x+) | Chậm |
| Quản lý khóa | Phức hợp (bí mật chung) | Dễ dàng hơn (công khai/riêng tư) |
| Kích thước khóa | 128-256 bit | Hơn 2048 bit |
| Trường hợp sử dụng | Mã hóa dữ liệu hàng loạt | Trao đổi khóa, chữ ký |
Mã hóa lai
Trong thực tế, các hệ thống sử dụng mã hóa hybrid: mã hóa bất đối xứng để trao đổi khóa đối xứng, sau đó mã hóa đối xứng cho dữ liệu thực tế.
1. Alice generates random AES key (symmetric)
2. Alice encrypts data with AES key
3. Alice encrypts AES key with Bob's RSA public key (asymmetric)
4. Alice sends: encrypted data + encrypted AES key
5. Bob decrypts AES key with his RSA private key
6. Bob decrypts data with AES key
Đây chính xác là cách TLS hoạt động (được đề cập trong Phần 3).
Các phương pháp hay nhất về quản lý khóa
Mã hóa chỉ mạnh bằng khả năng quản lý khóa của bạn. Dưới đây là những thực hành cần thiết:
1. Không bao giờ khóa mã cứng
# ❌ BAD: Key in source code
ENCRYPTION_KEY = "super_secret_key_123"
# ✅ GOOD: Key from environment/secrets manager
import os
ENCRYPTION_KEY = os.environ.get('ENCRYPTION_KEY')
# ✅ BETTER: Use a secrets manager
from aws_secretsmanager import get_secret
ENCRYPTION_KEY = get_secret('app/encryption-key')
2. Sử dụng dẫn xuất khóa hàm (KDF)
Khi lấy khóa từ mật khẩu, hãy sử dụng KDF thích hợp:
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.primitives import hashes
import os
import base64
def derive_key_from_password(password: str, salt: bytes = None) -> tuple[bytes, bytes]:
"""Derive a secure encryption key from a password."""
if salt is None:
salt = os.urandom(16)
kdf = PBKDF2HMAC(
algorithm=hashes.SHA256(),
length=32, # 256 bits for AES-256
salt=salt,
iterations=600000, # OWASP recommended minimum
)
key = kdf.derive(password.encode())
return key, salt
# Store the salt alongside encrypted data
password = "user_master_password"
key, salt = derive_key_from_password(password)
3. Xoay phím thường xuyên
# Example: AWS KMS key rotation policy
Resources:
EncryptionKey:
Type: AWS::KMS::Key
Properties:
EnableKeyRotation: true # Automatic annual rotation
KeyPolicy:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
AWS: !Sub 'arn:aws:iam::${AWS::AccountId}:root'
Action: 'kms:*'
Resource: '*'
4. Sử dụng Mô-đun bảo mật phần cứng (HSM) cho khóa có giá trị cao
Đối với hệ thống production xử lý dữ liệu nhạy cảm:
- AWS KMS / Cloud KMS / Azure Key Vault dành cho khối lượng công việc trên đám mây
- HashiCorp Vault dành cho nhiều đám mây hoặc tại chỗ
- HPhần cứng HSMs (Luna, nCipher) cho yêu cầu bảo mật cao nhất
Các lỗi mã hóa phổ biến
1. Sử dụng mã hóa mà không cần xác thực
# ❌ BAD: AES-CBC without MAC (vulnerable to padding oracle attacks)
cipher = Cipher(algorithms.AES(key), modes.CBC(iv))
# ✅ GOOD: AES-GCM (authenticated encryption)
aesgcm = AESGCM(key)
ciphertext = aesgcm.encrypt(nonce, plaintext, associated_data)
2. Tái sử dụng Nonces/IV
# ❌ BAD: Static nonce
NONCE = b"static_nonce" # Catastrophic for GCM!
# ✅ GOOD: Random nonce for each encryption
nonce = os.urandom(12)
3. Tạo khóa yếu
# ❌ BAD: Predictable key
import random
key = bytes([random.randint(0, 255) for _ in range(32)])
# ✅ GOOD: Cryptographically secure random
import os
key = os.urandom(32)
# ✅ ALSO GOOD: Library-provided generation
from cryptography.fernet import Fernet
key = Fernet.generate_key()
Mã hóa trong bối cảnh DevOps
Mã hóa bí mật trong CI/CD
# GitHub Actions: Using encrypted secrets
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy with encrypted credentials
env:
DB_PASSWORD: ${{ secrets.DB_PASSWORD }} # Decrypted at runtime
run: ./deploy.sh
Mã hóa dữ liệu ở phần còn lại
# AWS S3 bucket with server-side encryption
aws s3 cp sensitive-file.txt s3://my-bucket/ \
--sse aws:kms \
--sse-kms-key-id alias/my-key
# Kubernetes secrets encryption at rest
# In kube-apiserver configuration:
--encryption-provider-config=/etc/kubernetes/encryption-config.yaml
SOPS dành cho GitOps
# Encrypted with SOPS (secrets shown in plaintext for example)
# Actual file would have encrypted values
database:
password: ENC[AES256_GCM,data:abc123...]
host: ENC[AES256_GCM,data:def456...]
sops:
kms:
- arn:aws:kms:us-east-1:123456789:key/abc-123
encrypted_suffix: _encrypted
Tóm tắt
Những điểm chính của mã hóa:
- Mã hóa đối xứng (AES-256-GCM) cho dữ liệu số lượng lớn—nhanh nhưng yêu cầu trao đổi khóa an toàn
- Amã hóa đối xứng (RSA, ECDSA) để trao đổi khóa và chữ ký—giải quyết vấn đề phân phối
- Luôn sử dụng mã hóa xác thực (chế độ GCM)—không bao giờ mã hóa mà không bảo vệ tính toàn vẹn
- Không bao giờ sử dụng lại nonces/IVs—thảm họa đối với mật mã luồng và GCM
- Sử dụng quản lý khóa thích hợp—trình quản lý bí mật, KDF cho mật khẩu, luân chuyển thường xuyên
- Atránh các thuật toán không được dùng nữa—không có chế độ DES, 3DES, RC4 hoặc ECB
Trong phần tiếp theo, chúng ta sẽ khám phá tính năng băm—hàm một chiều được sử dụng để xác minh tính toàn vẹn và lưu trữ mật khẩu.