1. Pengenalan Kriptografi
Kriptografi adalah ilmu dan seni melindungi informasi melalui teknik penyandian (encoding). Dalam konteks pengembangan perangkat lunak, kriptografi adalah fondasi keamanan yang melindungi data baik saat disimpan (at rest), saat dikirim (in transit), maupun saat diproses (in use). Tanpa kriptografi, tidak akan ada e-commerce, internet banking, atau komunikasi privat di era digital.
Sebagai developer, memahami kriptografi bukan berarti Anda harus menjadi ahli matematika β tetapi Anda harus tahu kapan, mengapa, dan bagaimana menggunakan primitif kriptografi yang tepat. Menggunakan kriptografi yang salah bisa lebih berbahaya daripada tidak menggunakan sama sekali, karena memberikan rasa aman palsu (false sense of security).
Konsep Dasar Kriptografi
| Konsep | Penjelasan | Contoh |
|---|---|---|
| Plaintext | Data asli yang belum dienkripsi | "Rahasia123" |
| Ciphertext | Data yang sudah dienkripsi β tidak bisa dibaca | "xK9mP2nQ..." |
| Encryption | Proses mengubah plaintext menjadi ciphertext | AES, RSA |
| Decryption | Proses mengubah ciphertext kembali menjadi plaintext | Dengan kunci yang tepat |
| Key | Nilai rahasia yang digunakan untuk enkripsi/dekripsi | 256-bit random key |
| Algorithm | Prosedur matematika untuk enkripsi/dekripsi | AES-256-GCM |
| Hashing | Fungsi satu arah β tidak bisa dibalik | SHA-256, bcrypt |
Perbedaan Kriptografi Klasik vs Modern
| Aspek | Klasik | Modern |
|---|---|---|
| Basis | Substitusi & Transposisi huruf | Matematika & komputasi kompleks |
| Keamanan | Bisa dipecahkan dengan analisis frekuensi | Komputasional infeasible untuk dipecahkan |
| Contoh | Caesar Cipher, Vigenère, Enigma | AES, RSA, ECC, ChaCha20 |
| Penggunaan | Edukasi, puzzle | TLS, SSH, blockchain, e-commerce |
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β KRIPTOGRAFI β β β β ββββββββββββββββββββββββ βββββββββββββββββββββββββ β β β Symmetric Key β β Asymmetric Key β β β β (1 kunci) β β (2 kunci) β β β β β β β β β β AES, DES, 3DES β β RSA, ECC, DH β β β β ChaCha20, Blowfish β β Ed25519, X25519 β β β ββββββββββββββββββββββββ βββββββββββββββββββββββββ β β β β ββββββββββββββββββββββββ βββββββββββββββββββββββββ β β β Hashing β β Digital Signatures β β β β (One-way) β β (Autentikasi) β β β β β β β β β β SHA-256, SHA-3 β β RSA-SHA256 β β β β bcrypt, Argon2 β β ECDSA, EdDSA β β β β BLAKE2, HMAC β β β β β ββββββββββββββββββββββββ βββββββββββββββββββββββββ β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Gunakan selalu library dan algoritma yang sudah teruji dan divalidasi oleh komunitas kriptografi global. Membuat "security by obscurity" (algoritma rahasia) hampir selalu berakhir dengan kegagalan. Gunakan library seperti cryptography (Python), crypto (Node.js), atau OpenSSL.
2. Symmetric Encryption
Symmetric encryption menggunakan satu kunci yang sama untuk enkripsi dan dekripsi. Kunci ini harus dirahasiakan dan dikirim ke pihak lain melalui channel yang aman. Symmetric encryption jauh lebih cepat daripada asymmetric encryption, sehingga cocok untuk mengenkripsi data dalam volume besar.
AES (Advanced Encryption Standard)
AES adalah standar enkripsi symmetric yang paling banyak digunakan di dunia. Mendukung kunci 128, 192, dan 256 bit. Disetujui oleh NSA untuk informasi classified hingga TOP SECRET.
# Instalasi: pip install cryptography
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives import padding
from cryptography.hazmat.backends import default_backend
import os
# =============================================
# AES-256-CBC Encryption & Decryption
# =============================================
def generate_key():
"""Generate random 256-bit key"""
return os.urandom(32) # 32 bytes = 256 bits
def encrypt_aes_cbc(plaintext: str, key: bytes) -> bytes:
"""
Enkripsi menggunakan AES-256-CBC
plaintext: string yang akan dienkripsi
key: 32-byte key
Returns: IV + ciphertext
"""
# Generate random IV (Initialization Vector)
iv = os.urandom(16) # 16 bytes = 128 bits (block size)
# Padding plaintext ke multiple of block size (128 bit)
padder = padding.PKCS7(128).padder()
padded_data = padder.update(plaintext.encode('utf-8')) + padder.finalize()
# Enkripsi
cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend())
encryptor = cipher.encryptor()
ciphertext = encryptor.update(padded_data) + encryptor.finalize()
# Gabungkan IV + ciphertext (IV tidak rahasia, tapi harus unik)
return iv + ciphertext
def decrypt_aes_cbc(encrypted_data: bytes, key: bytes) -> str:
"""
Dekripsi AES-256-CBC
encrypted_data: IV + ciphertext
key: 32-byte key (harus sama dengan yang digunakan saat enkripsi)
Returns: plaintext string
"""
# Pisahkan IV dan ciphertext
iv = encrypted_data[:16]
ciphertext = encrypted_data[16:]
# Dekripsi
cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend())
decryptor = cipher.decryptor()
padded_plaintext = decryptor.update(ciphertext) + decryptor.finalize()
# Hapus padding
unpadder = padding.PKCS7(128).unpadder()
plaintext = unpadder.update(padded_plaintext) + unpadder.finalize()
return plaintext.decode('utf-8')
# ===== CONTOH PENGGUNAAN =====
key = generate_key()
pesan_rahasia = "Data sensitif: nomor kartu kredit 4111-1111-1111-1111"
# Enkripsi
encrypted = encrypt_aes_cbc(pesan_rahasia, key)
print(f"Ciphertext (hex): {encrypted.hex()[:64]}...")
# Dekripsi
decrypted = decrypt_aes_cbc(encrypted, key)
print(f"Plaintext: {decrypted}")
# Verifikasi
assert decrypted == pesan_rahasia
print("β
Enkripsi dan dekripsi berhasil!")
AES-GCM (Authenticated Encryption)
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import os
# =============================================
# AES-256-GCM β Authenticated Encryption
# AES-GCM lebih aman karena menyertakan integrity check (authentication tag)
# Direkomendasikan untuk sebagian besar use case
# =============================================
def encrypt_aes_gcm(plaintext: str, key: bytes, associated_data: bytes = None) -> bytes:
"""
AES-256-GCM Encryption
- Plaintext: data yang akan dienkripsi
- Key: 32-byte key
- Associated data: data yang ikut di-authenticate tapi tidak dienkripsi
(misal: header, context)
Returns: nonce + ciphertext + tag
"""
aesgcm = AESGCM(key)
# Generate unique nonce (12 bytes direkomendasikan untuk GCM)
nonce = os.urandom(12)
# Enkripsi + Authenticate
# Hasil sudah termasuk authentication tag
ciphertext = aesgcm.encrypt(nonce, plaintext.encode('utf-8'), associated_data)
return nonce + ciphertext
def decrypt_aes_gcm(encrypted_data: bytes, key: bytes, associated_data: bytes = None) -> str:
"""
AES-256-GCM Decryption
- Akan raise InvalidTag exception jika data dimanipulasi!
"""
aesgcm = AESGCM(key)
# Pisahkan nonce dan ciphertext
nonce = encrypted_data[:12]
ciphertext = encrypted_data[12:]
# Dekripsi + Verify authenticity
plaintext = aesgcm.decrypt(nonce, ciphertext, associated_data)
return plaintext.decode('utf-8')
# ===== CONTOH =====
key = AESGCM.generate_key(bit_length=256)
pesan = "Pesan rahasia untuk CEO"
# Dengan additional authenticated data (AAD)
context = b"user:admin,session:abc123"
encrypted = encrypt_aes_gcm(pesan, key, associated_data=context)
decrypted = decrypt_aes_gcm(encrypted, key, associated_data=context)
print(f"Encrypted: {encrypted.hex()[:64]}...")
print(f"Decrypted: {decrypted}")
# Jika AAD dimanipulasi, dekripsi akan GAGAL!
Gunakan AES-GCM sebagai default. GCM memberikan authenticated encryption β selain mengenkripsi data, ia juga memverifikasi integritas data. Jika data diubah oleh penyerang, dekripsi akan gagal dengan error InvalidTag. CBC hanya mengenkripsi tanpa verifikasi integritas, sehingga rentan terhadap padding oracle attack.
Perbandingan Algoritma Symmetric
| Algoritma | Key Size | Kecepatan | Keamanan | Rekomendasi |
|---|---|---|---|---|
| AES-256-GCM | 256-bit | π’ Cepat (hardware) | π’ Sangat Aman | β Utama |
| ChaCha20-Poly1305 | 256-bit | π’ Cepat (software) | π’ Sangat Aman | β Mobile/IoT |
| AES-256-CBC | 256-bit | π’ Cepat | π‘ Perlu HMAC | β οΈ Legacy |
| 3DES | 168-bit | π΄ Lambat | π‘ Lemah | β Hindari |
| DES | 56-bit | π‘ Sedang | π΄ Pecah | β Jangan gunakan |
| RC4 | Variable | π’ Cepat | π΄ Pecah | β Jangan gunakan |
3. Asymmetric Encryption
Asymmetric encryption (atau public-key cryptography) menggunakan sepasang kunci: satu public key (bisa dibagikan) dan satu private key (harus dirahasiakan). Apa yang dienkripsi dengan satu kunci hanya bisa didekripsi dengan kunci pasangannya. Ini menyelesaikan masalah distribusi kunci yang menjadi kelemahan symmetric encryption.
RSA Encryption
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.backends import default_backend
# =============================================
# RSA β Asymmetric Encryption
# =============================================
def generate_rsa_keypair(key_size=4096):
"""Generate RSA key pair (private + public)"""
private_key = rsa.generate_private_key(
public_exponent=65537, # Standar, jangan diubah
key_size=key_size, # 2048 minimum, 4096 direkomendasikan
backend=default_backend()
)
public_key = private_key.public_key()
return private_key, public_key
def rsa_encrypt(plaintext: str, public_key) -> bytes:
"""Enkripsi dengan public key (siapapun bisa melakukan ini)"""
ciphertext = public_key.encrypt(
plaintext.encode('utf-8'),
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
return ciphertext
def rsa_decrypt(ciphertext: bytes, private_key) -> str:
"""Dekripsi dengan private key (hanya pemilik yang bisa)"""
plaintext = private_key.decrypt(
ciphertext,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
return plaintext.decode('utf-8')
# ===== CONTOH =====
# Alice generate key pair
alice_private, alice_public = generate_rsa_keypair()
# Bob mengenkripsi pesan dengan public key Alice
pesan_dari_bob = "Halo Alice, ini pesan rahasia dari Bob!"
encrypted = rsa_encrypt(pesan_dari_bob, alice_public)
# Alice mendekripsi dengan private key-nya
decrypted = rsa_decrypt(encrypted, alice_private)
print(f"Pesan dari Bob: {decrypted}")
# HANYA Alice yang bisa membaca pesan ini!
# Simpan key ke file
private_pem = alice_private.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.BestAvailableEncryption(b"password123")
)
public_pem = alice_public.public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo
)
print(f"Public Key:\n{public_pem.decode()[:200]}...")
Diffie-Hellman Key Exchange
Diffie-Hellman memungkinkan dua pihak membuat shared secret di atas channel yang tidak aman β tanpa harus mengirim kunci secara langsung. Ini adalah fondasi dari TLS/SSL.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β DIFFIE-HELLMAN KEY EXCHANGE β β β β ALICE BOB β β ββββββββββββ ββββββββββββ β β β Private a β β Private b β β β β Public A β β Public B β β β ββββββ¬βββββββ ββββββ¬βββββββ β β β β β β β Kirim A βββββββββββββββββββββββΆβ β β β β β β ββββββββββββββββββββββ Kirim B β β β β β β β βΌ βΌ β β Shared Secret = B^a Shared Secret = A^b β β = (g^b)^a = (g^a)^b β β = g^(ab) = g^(ab) β β β β β β βββββββββ SAMA! βββββββββββββββββ β β β β Penyerang hanya melihat A dan B β β TIDAK BISA menghitung g^(ab) tanpa a atau b β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ECC (Elliptic Curve Cryptography)
| Aspek | RSA | ECC |
|---|---|---|
| Key Size untuk keamanan sama | 3072-bit | 256-bit |
| Kecepatan | π‘ Lebih lambat | π’ Lebih cepat |
| Ukuran signature | Besar | Kecil |
| Cocok untuk | Legacy systems | Mobile, IoT, TLS modern |
| Contoh kurva | β | Curve25519, P-256, secp256k1 |
4. Hashing & HMAC
Hashing adalah fungsi satu arah (one-way function) yang mengubah input berapapun panjangnya menjadi output tetap (fixed-length) yang disebut hash atau digest. Berbeda dengan enkripsi, hashing TIDAK BISA DIBALIK β Anda tidak bisa mendapatkan input asli dari hash-nya. Hashing digunakan untuk verifikasi integritas data dan penyimpanan password.
Cryptographic Hash Functions
import hashlib
import hmac
import os
import bcrypt
# =============================================
# HASHING β One-way function
# =============================================
# 1. SHA-256 β General purpose hashing
data = "Hello, World!"
sha256_hash = hashlib.sha256(data.encode()).hexdigest()
print(f"SHA-256: {sha256_hash}")
# Output: dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f
# Setiap perubahan kecil menghasilkan hash yang sangat berbeda
sha256_hash2 = hashlib.sha256("Hello, World.".encode()).hexdigest()
print(f"SHA-256 (titik berubah): {sha256_hash2}")
# Output: COMPLETELY different hash!
# 2. File integrity check
def hash_file(filepath):
"""Hitung hash SHA-256 dari file"""
sha256 = hashlib.sha256()
with open(filepath, 'rb') as f:
for chunk in iter(lambda: f.read(8192), b''):
sha256.update(chunk)
return sha256.hexdigest()
# Contoh: verifikasi download
expected_hash = "abc123..."
downloaded_hash = hash_file("downloaded_file.zip")
if downloaded_hash == expected_hash:
print("β
File utuh, tidak dimodifikasi!")
else:
print("β File sudah dimodifikasi atau corrupt!")
# 3. HMAC β Hash-based Message Authentication Code
# Memverifikasi integritas DAN autentikasi pesan
secret_key = b"my-secret-key-here"
message = "Transfer $1000 to Alice"
# Membuat HMAC
hmac_digest = hmac.new(secret_key, message.encode(), hashlib.sha256).hexdigest()
print(f"HMAC: {hmac_digest}")
# Verifikasi HMAC
is_valid = hmac.compare_digest(
hmac.new(secret_key, message.encode(), hashlib.sha256).hexdigest(),
hmac_digest
)
print(f"Valid: {is_valid}") # True
# β Attacker mengubah message
fake_message = "Transfer $9999 to Eve"
is_valid_fake = hmac.compare_digest(
hmac.new(secret_key, fake_message.encode(), hashlib.sha256).hexdigest(),
hmac_digest
)
print(f"Fake valid: {is_valid_fake}") # False!
Password Hashing
# β JANGAN gunakan SHA-256 untuk password!
# SHA-256 terlalu cepat β attacker bisa brute force miliaran hash/detik
# β
Gunakan bcrypt atau Argon2 β dirancang khusus untuk password
# Mereka SENGAJA lambat dan menggunakan salt otomatis
# === BCRYPT ===
import bcrypt
def hash_password_bcrypt(password: str) -> bytes:
"""Hash password dengan bcrypt (salt otomatis)"""
salt = bcrypt.gensalt(rounds=12) # Cost factor 12 (direkomendasikan)
password_hash = bcrypt.hashpw(password.encode('utf-8'), salt)
return password_hash
def verify_password_bcrypt(password: str, hashed: bytes) -> bool:
"""Verifikasi password terhadap hash"""
return bcrypt.checkpw(password.encode('utf-8'), hashed)
# Contoh
password = "MyS3cur3P@ssw0rd!"
hashed = hash_password_bcrypt(password)
print(f"Hash: {hashed}")
# Output: $2b$12$LJ3m4ys3Gl5Jo4S8V... (salt embedded dalam hash)
print(f"Verifikasi benar: {verify_password_bcrypt(password, hashed)}") # True
print(f"Verifikasi salah: {verify_password_bcrypt('wrong', hashed)}") # False
# === ARGON2 (lebih modern, direkomendasikan oleh OWASP) ===
# pip install argon2-cffi
from argon2 import PasswordHasher
from argon2.exceptions import VerifyMismatchError
ph = PasswordHasher(
time_cost=3, # Iterasi
memory_cost=65536, # 64 MB memory
parallelism=4, # 4 threads
)
def hash_password_argon2(password: str) -> str:
return ph.hash(password)
def verify_password_argon2(password: str, hashed: str) -> bool:
try:
return ph.verify(hashed, password)
except VerifyMismatchError:
return False
hashed_argon2 = hash_password_argon2(password)
print(f"Argon2 hash: {hashed_argon2}")
print(f"Verifikasi: {verify_password_argon2(password, hashed_argon2)}")
Perbandingan Hash Functions
| Algoritma | Output | Kecepatan | Penggunaan | Status |
|---|---|---|---|---|
| SHA-256 | 256-bit | Sangat cepat | Integrity check, digital signatures | β Aman |
| SHA-3 | Variable | Cepat | Alternative ke SHA-2 | β Aman |
| bcrypt | 184-bit | Sengaja lambat | Password hashing | β Aman |
| Argon2id | Variable | Configurable | Password hashing (terbaru) | β Terbaik |
| BLAKE2 | Variable | Sangat cepat | Alternative ke SHA-3 | β Aman |
| MD5 | 128-bit | Cepat | HANYA checksum non-security | β Pecah |
| SHA-1 | 160-bit | Cepat | Hindari | β Pecah |
5. Digital Signatures
Digital signatures memecahkan dua masalah sekaligus: autentikasi (memverifikasi identitas pengirim) dan integritas (memastikan data tidak dimodifikasi). Konsepnya mirip dengan tanda tangan basah di dunia nyata β tetapi jauh lebih aman karena tidak bisa dipalsukan secara kriptografis.
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from cryptography.hazmat.primitives import serialization
# =============================================
# DIGITAL SIGNATURES β Ed25519
# Ed25519: cepat, aman, signature kecil (64 bytes)
# =============================================
def generate_signing_keypair():
"""Generate key pair untuk signing"""
private_key = Ed25519PrivateKey.generate()
public_key = private_key.private_key.public_key()
return private_key, public_key
def sign_message(message: str, private_key) -> bytes:
"""Buat digital signature untuk pesan"""
return private_key.sign(message.encode('utf-8'))
def verify_signature(message: str, signature: bytes, public_key) -> bool:
"""Verifikasi digital signature"""
try:
public_key.verify(signature, message.encode('utf-8'))
return True
except Exception:
return False
# ===== CONTOH: ALICE MENGIRIM PESAN SIGNED =====
# Alice generate key pair
alice_private, alice_public = generate_signing_keypair()
# Alice menandatangani pesan
pesan = "Transfer $5000 ke rekening Bob"
signature = sign_message(pesan, alice_private)
print(f"Pesan: {pesan}")
print(f"Signature: {signature.hex()[:64]}...")
# Siapapun dengan public key Alice bisa memverifikasi
is_valid = verify_signature(pesan, signature, alice_public)
print(f"Signature valid: {is_valid}") # True
# Attacker mencoba memodifikasi pesan
pesan_dimodifikasi = "Transfer $50000 ke rekening Eve"
is_valid_mod = verify_signature(pesan_dimodifikasi, signature, alice_public)
print(f"Modified valid: {is_valid_mod}") # False!
# Attacker mencoba memalsukan signature
fake_signature = b"fake_signature_here"
is_valid_fake = verify_signature(pesan, fake_signature, alice_public)
print(f"Fake valid: {is_valid_fake}") # False!
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β DIGITAL SIGNATURE FLOW β β β β PENANDA TANGAN (Alice) β β ββββββββββββ ββββββββββββ ββββββββββββββββ β β β Pesan βββββΆβ Hash βββββΆβ Sign with β β β β Asli β β (SHA) β β Private Key β β β ββββββββββββ ββββββββββββ ββββββββ¬ββββββββ β β β β β ββββββββββββββΌββββββββββββ β β βΌ βΌ β β β ββββββββββ ββββββββββββ β β β β Pesan β β Signatureβ β β β ββββββ¬ββββ ββββββ¬ββββββ β β β β β β β β PEMVERIFIKASI (Bob) β β β β β βββββββββββββββββββββββββββΌββββββββββββ β β β β βΌ β β β β ββββββββββββ ββββββββββββ β β β β β Hash ββββββ Pesan β β β β β β Pesan β β + Sign β β β β β ββββββ¬ββββββ ββββββ¬ββββββ β β β β β β β β β β βΌ βΌ β β β β ββββββββββββββββββββββββββββ β β β β β Verify with Public Key β β β β β β Hash == Decrypt(Sign)? β β β β β ββββββββββββββ¬ββββββββββββββ β β β β βΌ β β β β β VALID / β INVALID β β β βββββββββββββββββββββββββββββββββββββββββββββββββββββ β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
6. TLS/SSL (Transport Layer Security)
TLS (Transport Layer Security) adalah protokol kriptografi yang mengamankan komunikasi di internet. Setiap kali Anda melihat https:// di browser, itu berarti koneksi Anda dilindungi oleh TLS. TLS menggunakan kombinasi symmetric encryption (untuk kecepatan) dan asymmetric encryption (untuk pertukaran kunci awal) β ini disebut hybrid encryption.
TLS Handshake
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β TLS 1.3 HANDSHAKE β β β β CLIENT (Browser) SERVER (Website) β β ββββββββββββ ββββββββββββ β β β Client β β β β β β Hello βββββ TLS Version βββΆβ β β β β β Cipher Suites β β β β β β Key Share β β β β ββββββββββββ ββββββββββββ β β ββββββββββββ β β β Server β β β β Hello β β β βββββ Selected Cipher ββββββ β β β βββββ Certificate ββββββββββ β β β βββββ Key Share ββββββββββββ β β β ββββββββββββ β β ββββββββββββ ββββββββββββ β β β Verify β β β β β β Cert β β β β β β Generate β β β β β β Session β β β β β β Key β β β β β ββββββ¬ββββββ ββββββ¬ββββββ β β β β β β βΌ βΌ β β ββββββββββββββββββββββββββββββββββββββββββββ β β β SECURE SYMMETRIC ENCRYPTED CHANNEL β β β β (AES-256-GCM / ChaCha20-Poly1305) β β β ββββββββββββββββββββββββββββββββββββββββββββ β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Konfigurasi TLS yang Aman
import ssl
import socket
# =============================================
# TLS β Konfigurasi yang Aman
# =============================================
def create_secure_ssl_context():
"""Buat SSL context yang aman"""
context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
# Minimum TLS 1.2 β TLS 1.0 dan 1.1 sudah tidak aman
context.minimum_version = ssl.TLSVersion.TLSv1_2
# Verifikasi sertifikat server
context.check_hostname = True
context.verify_mode = ssl.CERT_REQUIRED
# Load CA certificates
context.load_default_certs()
# Setel cipher suite yang aman
context.set_ciphers(
'ECDHE+AESGCM:ECDHE+CHACHA20:DHE+AESGCM:DHE+CHACHA20:!aNULL:!MD5:!DSS'
)
return context
def secure_request(host, port=443):
"""Koneksi HTTPS yang aman"""
context = create_secure_ssl_context()
with socket.create_connection((host, port)) as sock:
with context.wrap_socket(sock, server_hostname=host) as ssock:
# Informasi koneksi TLS
print(f"TLS Version: {ssock.version()}")
print(f"Cipher: {ssock.cipher()[0]}")
print(f"Server cert: {ssock.getpeercert()['subject']}")
# Kirim HTTP request
request = f"GET / HTTP/1.1\r\nHost: {host}\r\nConnection: close\r\n\r\n"
ssock.send(request.encode())
# Baca response
response = ssock.recv(4096)
print(f"Response: {response.decode()[:200]}...")
# Contoh
# secure_request("beebanelabs.pages.dev")
- Minimum TLS 1.2 β TLS 1.0 dan 1.1 sudah deprecated dan tidak aman
- Prefer TLS 1.3 β lebih cepat dan lebih aman (0-RTT, simplified handshake)
- Hapus cipher suites lemah: RC4, DES, 3DES, NULL, EXPORT
- Gunakan HSTS β Force browser untuk selalu menggunakan HTTPS
- Perfect Forward Secrecy (PFS) β Gunakan ECDHE key exchange
- Renew sertifikat sebelum expired β gunakan Let's Encrypt untuk otomatisasi
7. Public Key Infrastructure (PKI)
PKI (Public Key Infrastructure) adalah kerangka kerja yang mengelola pembuatan, distribusi, penyimpanan, dan pencabutan sertifikat digital. PKI memungkinkan kita mempercayai public key milik pihak lain β karena dijamin oleh Certificate Authority (CA) yang terpercaya. Tanpa PKI, tidak akan ada HTTPS, email terenkripsi, atau kode signing yang terverifikasi.
Komponen PKI
| Komponen | Fungsi | Contoh |
|---|---|---|
| Certificate Authority (CA) | Menerbitkan dan menandatangani sertifikat digital | Let's Encrypt, DigiCert, GlobalSign |
| Digital Certificate | Dokumen yang mengikat public key ke identitas | X.509 certificate |
| Certificate Chain | Rantai kepercayaan dari root CA ke end-entity cert | Root CA β Intermediate CA β Server cert |
| CRL / OCSP | Daftar sertifikat yang dicabut | Certificate Revocation List |
| Registration Authority (RA) | Memverifikasi identitas sebelum sertifikat diterbitkan | Domain validation, organization validation |
from cryptography import x509
from cryptography.x509.oid import NameOID
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import serialization
import datetime
# =============================================
# SELF-SIGNED CERTIFICATE β untuk development
# Untuk production, gunakan CA seperti Let's Encrypt
# =============================================
def generate_self_signed_cert(hostname="localhost"):
"""Generate self-signed certificate untuk development"""
# Generate private key
private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048,
)
# Buat self-signed certificate
subject = issuer = x509.Name([
x509.NameAttribute(NameOID.COUNTRY_NAME, "ID"),
x509.NameAttribute(NameOID.STATE, "Jakarta"),
x509.NameAttribute(NameOID.ORGANIZATION_NAME, "BeebaneLabs"),
x509.NameAttribute(NameOID.COMMON_NAME, hostname),
])
cert = (
x509.CertificateBuilder()
.subject_name(subject)
.issuer_name(issuer)
.public_key(private_key.public_key())
.serial_number(x509.random_serial_number())
.not_valid_before(datetime.datetime.utcnow())
.not_valid_after(datetime.datetime.utcnow() + datetime.timedelta(days=365))
.add_extension(
x509.SubjectAlternativeName([
x509.DNSName(hostname),
x509.DNSName(f"www.{hostname}"),
x509.IPAddress(ipaddress.IPv4Address("127.0.0.1")),
]),
critical=False,
)
.sign(private_key, hashes.SHA256())
)
# Simpan ke file
with open("server.key", "wb") as f:
f.write(private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.NoEncryption(),
))
with open("server.crt", "wb") as f:
f.write(cert.public_bytes(serialization.Encoding.PEM))
return private_key, cert
# Untuk production: gunakan Let's Encrypt (gratis!)
# sudo certbot certonly --standalone -d yourdomain.com
# Auto-renew: certbot renew --dry-run
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β CERTIFICATE CHAIN (PKI) β β β β βββββββββββββββββββββββββββ β β β ROOT CA β β Self-signed β β β (Disimpan di browser/OS)β Trusted by default β β βββββββββββββ¬ββββββββββββββ β β β Signs β β βΌ β β βββββββββββββββββββββββββββ β β β INTERMEDIATE CA β β Signed by Root CA β β β (Let's Encrypt R3) β β β βββββββββββββ¬ββββββββββββββ β β β Signs β β βΌ β β βββββββββββββββββββββββββββ β β β END-ENTITY CERT β β Signed by Intermediateβ β β (beebanelabs.pages.dev) β β β β Public Key + Identity β β β βββββββββββββββββββββββββββ β β β β Browser memverifikasi dari bottom ke top β β Jika salah satu link rusak β "Not Secure" β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
8. Quiz: Uji Pemahamanmu!
Setelah membaca tutorial di atas, jawablah 5 pertanyaan berikut untuk menguji pemahamanmu tentang Kriptografi: