Keamanan

Kriptografi untuk Developer

Panduan lengkap memahami kriptografi bagi developer β€” symmetric dan asymmetric encryption, hashing, digital signatures, TLS/SSL, PKI, dengan contoh kode Python yang bisa langsung dipraktikkan

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
PlaintextData asli yang belum dienkripsi"Rahasia123"
CiphertextData yang sudah dienkripsi β€” tidak bisa dibaca"xK9mP2nQ..."
EncryptionProses mengubah plaintext menjadi ciphertextAES, RSA
DecryptionProses mengubah ciphertext kembali menjadi plaintextDengan kunci yang tepat
KeyNilai rahasia yang digunakan untuk enkripsi/dekripsi256-bit random key
AlgorithmProsedur matematika untuk enkripsi/dekripsiAES-256-GCM
HashingFungsi satu arah β€” tidak bisa dibalikSHA-256, bcrypt

Perbedaan Kriptografi Klasik vs Modern

Aspek Klasik Modern
BasisSubstitusi & Transposisi hurufMatematika & komputasi kompleks
KeamananBisa dipecahkan dengan analisis frekuensiKomputasional infeasible untuk dipecahkan
ContohCaesar Cipher, Vigenère, EnigmaAES, RSA, ECC, ChaCha20
PenggunaanEdukasi, puzzleTLS, SSH, blockchain, e-commerce
Diagram: Jenis-Jenis Kriptografi
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                  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        β”‚  β”‚                       β”‚ β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
⚠️ Jangan Pernah Membuat Algoritma Kriptografi Sendiri!

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.

Python β€” AES Encryption dengan library cryptography
# 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)

Python β€” AES-256-GCM (Recommended)
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!
πŸ’‘ CBC vs GCM β€” Mana yang Harus Digunakan?

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-GCM256-bit🟒 Cepat (hardware)🟒 Sangat Amanβœ… Utama
ChaCha20-Poly1305256-bit🟒 Cepat (software)🟒 Sangat Amanβœ… Mobile/IoT
AES-256-CBC256-bit🟒 Cepat🟑 Perlu HMAC⚠️ Legacy
3DES168-bitπŸ”΄ Lambat🟑 Lemah❌ Hindari
DES56-bit🟑 SedangπŸ”΄ Pecah❌ Jangan gunakan
RC4Variable🟒 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

Python β€” RSA Encryption & Key Generation
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.

Diagram: Diffie-Hellman Key Exchange
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚           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 sama3072-bit256-bit
Kecepatan🟑 Lebih lambat🟒 Lebih cepat
Ukuran signatureBesarKecil
Cocok untukLegacy systemsMobile, 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

Python β€” Hashing
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

Python β€” Password Hashing dengan bcrypt & Argon2
# ❌ 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-256256-bitSangat cepatIntegrity check, digital signaturesβœ… Aman
SHA-3VariableCepatAlternative ke SHA-2βœ… Aman
bcrypt184-bitSengaja lambatPassword hashingβœ… Aman
Argon2idVariableConfigurablePassword hashing (terbaru)βœ… Terbaik
BLAKE2VariableSangat cepatAlternative ke SHA-3βœ… Aman
MD5128-bitCepatHANYA checksum non-security❌ Pecah
SHA-1160-bitCepatHindari❌ 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.

Python β€” Digital Signatures dengan Ed25519
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!
Diagram: Alur Digital Signature
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚            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

Diagram: TLS 1.3 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

Python β€” TLS Configuration
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")
⚠️ TLS Best Practices
  • 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 digitalLet's Encrypt, DigiCert, GlobalSign
Digital CertificateDokumen yang mengikat public key ke identitasX.509 certificate
Certificate ChainRantai kepercayaan dari root CA ke end-entity certRoot CA β†’ Intermediate CA β†’ Server cert
CRL / OCSPDaftar sertifikat yang dicabutCertificate Revocation List
Registration Authority (RA)Memverifikasi identitas sebelum sertifikat diterbitkanDomain validation, organization validation
Python β€” Membuat Self-Signed Certificate
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
Diagram: Certificate Chain
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚           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:

Pertanyaan 1: Apa perbedaan utama antara symmetric dan asymmetric encryption?

a) Symmetric lebih aman dari asymmetric
b) Symmetric menggunakan 1 kunci, asymmetric menggunakan 2 kunci (public & private)
c) Asymmetric lebih cepat dari symmetric
d) Tidak ada perbedaan

Pertanyaan 2: Mengapa SHA-256 TIDAK cocok untuk hashing password?

a) Karena SHA-256 terlalu pendek
b) Karena SHA-256 terlalu cepat β€” attacker bisa brute force miliaran hash/detik
c) Karena SHA-256 bukan fungsi hash
d) Karena SHA-256 bisa dibalik (reversible)

Pertanyaan 3: Apa yang dijamin oleh digital signature?

a) Kerahasiaan data
b) Autentikasi pengirim dan integritas data
c) Kompresi data
d) Enkripsi data

Pertanyaan 4: Algoritma symmetric encryption apa yang paling direkomendasikan saat ini?

a) DES
b) RC4
c) AES-256-GCM
d) MD5

Pertanyaan 5: Apa fungsi utama Certificate Authority (CA) dalam PKI?

a) Mengenkripsi semua data di internet
b) Mengelola password pengguna
c) Menerbitkan dan menandatangani sertifikat digital yang mengikat public key ke identitas
d) Membuat algoritma kriptografi baru