Skip to content

Cryptography Basics


Cryptography Overview

Cryptography Overview


Symmetric Encryption

Symmetric Encryption

Block Cipher Modes

Block Cipher Modes

AES-GCM Implementation

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import java.security.SecureRandom;

public class AesGcmEncryption {

    private static final int GCM_IV_LENGTH = 12;  // 96 bits recommended
    private static final int GCM_TAG_LENGTH = 128; // bits

    public byte[] encrypt(byte[] plaintext, SecretKey key) throws Exception {
        // Generate random IV
        byte[] iv = new byte[GCM_IV_LENGTH];
        SecureRandom random = new SecureRandom();
        random.nextBytes(iv);

        // Initialize cipher
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH, iv);
        cipher.init(Cipher.ENCRYPT_MODE, key, spec);

        // Encrypt
        byte[] ciphertext = cipher.doFinal(plaintext);

        // Prepend IV to ciphertext (IV || Ciphertext || Tag)
        byte[] result = new byte[iv.length + ciphertext.length];
        System.arraycopy(iv, 0, result, 0, iv.length);
        System.arraycopy(ciphertext, 0, result, iv.length, ciphertext.length);

        return result;
    }

    public byte[] decrypt(byte[] encryptedData, SecretKey key) throws Exception {
        // Extract IV
        byte[] iv = new byte[GCM_IV_LENGTH];
        System.arraycopy(encryptedData, 0, iv, 0, iv.length);

        // Extract ciphertext
        byte[] ciphertext = new byte[encryptedData.length - GCM_IV_LENGTH];
        System.arraycopy(encryptedData, GCM_IV_LENGTH, ciphertext, 0, ciphertext.length);

        // Initialize cipher
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH, iv);
        cipher.init(Cipher.DECRYPT_MODE, key, spec);

        // Decrypt and verify
        return cipher.doFinal(ciphertext);
    }

    public SecretKey generateKey() throws Exception {
        KeyGenerator keyGen = KeyGenerator.getInstance("AES");
        keyGen.init(256, new SecureRandom());
        return keyGen.generateKey();
    }
}

Asymmetric Encryption (Public Key)

Asymmetric Encryption

RSA Implementation

import java.security.*;
import javax.crypto.Cipher;

public class RsaEncryption {

    public KeyPair generateKeyPair() throws Exception {
        KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
        generator.initialize(2048, new SecureRandom());
        return generator.generateKeyPair();
    }

    public byte[] encrypt(byte[] plaintext, PublicKey publicKey) throws Exception {
        Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        return cipher.doFinal(plaintext);
    }

    public byte[] decrypt(byte[] ciphertext, PrivateKey privateKey) throws Exception {
        Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        return cipher.doFinal(ciphertext);
    }
}

Digital Signatures

import java.security.*;

public class DigitalSignature {

    public byte[] sign(byte[] data, PrivateKey privateKey) throws Exception {
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initSign(privateKey);
        signature.update(data);
        return signature.sign();
    }

    public boolean verify(byte[] data, byte[] signatureBytes,
                          PublicKey publicKey) throws Exception {
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initVerify(publicKey);
        signature.update(data);
        return signature.verify(signatureBytes);
    }
}

// Ed25519 (modern, recommended)
public class Ed25519Signature {

    public KeyPair generateKeyPair() throws Exception {
        KeyPairGenerator generator = KeyPairGenerator.getInstance("Ed25519");
        return generator.generateKeyPair();
    }

    public byte[] sign(byte[] data, PrivateKey privateKey) throws Exception {
        Signature signature = Signature.getInstance("Ed25519");
        signature.initSign(privateKey);
        signature.update(data);
        return signature.sign();
    }

    public boolean verify(byte[] data, byte[] sig,
                          PublicKey publicKey) throws Exception {
        Signature signature = Signature.getInstance("Ed25519");
        signature.initVerify(publicKey);
        signature.update(data);
        return signature.verify(sig);
    }
}

Hybrid Encryption

Hybrid Encryption

public class HybridEncryption {

    public EncryptedMessage encrypt(byte[] plaintext, PublicKey recipientPublicKey)
            throws Exception {
        // Generate random AES key
        KeyGenerator keyGen = KeyGenerator.getInstance("AES");
        keyGen.init(256, new SecureRandom());
        SecretKey sessionKey = keyGen.generateKey();

        // Encrypt data with AES
        AesGcmEncryption aes = new AesGcmEncryption();
        byte[] encryptedData = aes.encrypt(plaintext, sessionKey);

        // Encrypt session key with RSA
        RsaEncryption rsa = new RsaEncryption();
        byte[] encryptedKey = rsa.encrypt(sessionKey.getEncoded(), recipientPublicKey);

        return new EncryptedMessage(encryptedKey, encryptedData);
    }

    public byte[] decrypt(EncryptedMessage message, PrivateKey recipientPrivateKey)
            throws Exception {
        // Decrypt session key
        RsaEncryption rsa = new RsaEncryption();
        byte[] sessionKeyBytes = rsa.decrypt(message.getEncryptedKey(), recipientPrivateKey);
        SecretKey sessionKey = new SecretKeySpec(sessionKeyBytes, "AES");

        // Decrypt data
        AesGcmEncryption aes = new AesGcmEncryption();
        return aes.decrypt(message.getEncryptedData(), sessionKey);
    }
}

Hashing

Hash Functions

import java.security.MessageDigest;

public class HashingExample {

    public byte[] sha256(byte[] data) throws Exception {
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        return digest.digest(data);
    }

    public String sha256Hex(String input) throws Exception {
        byte[] hash = sha256(input.getBytes(StandardCharsets.UTF_8));
        return bytesToHex(hash);
    }

    private String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }
}

Password Hashing

Password Hashing

bcrypt Implementation

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

public class PasswordService {

    // Cost factor: 2^12 = 4096 iterations
    // Increase over time as hardware improves
    private final BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(12);

    public String hashPassword(String rawPassword) {
        // Salt is automatically generated and stored in the hash
        return encoder.encode(rawPassword);
    }

    public boolean verifyPassword(String rawPassword, String hashedPassword) {
        return encoder.matches(rawPassword, hashedPassword);
    }
}

// bcrypt hash format:
// $2a$12$R9h/cIPz0gi.URNNX3kh2OPST9/PgBkqquzi.Ss7KIUgO2t0jWMUW
// $2a$ = algorithm identifier
// 12   = cost factor
// R9h/cIPz0gi.URNNX3kh2O = salt (22 chars)
// PST9/PgBkqquzi.Ss7KIUgO2t0jWMUW = hash (31 chars)

Argon2 Implementation

import org.bouncycastle.crypto.generators.Argon2BytesGenerator;
import org.bouncycastle.crypto.params.Argon2Parameters;

public class Argon2PasswordService {

    private static final int SALT_LENGTH = 16;
    private static final int HASH_LENGTH = 32;
    private static final int PARALLELISM = 1;
    private static final int MEMORY = 65536;  // 64 MB
    private static final int ITERATIONS = 3;

    public String hashPassword(String password) {
        byte[] salt = new byte[SALT_LENGTH];
        new SecureRandom().nextBytes(salt);

        Argon2Parameters params = new Argon2Parameters.Builder(Argon2Parameters.ARGON2_id)
            .withSalt(salt)
            .withParallelism(PARALLELISM)
            .withMemoryAsKB(MEMORY)
            .withIterations(ITERATIONS)
            .build();

        Argon2BytesGenerator generator = new Argon2BytesGenerator();
        generator.init(params);

        byte[] hash = new byte[HASH_LENGTH];
        generator.generateBytes(password.toCharArray(), hash);

        // Encode salt + hash for storage
        return Base64.getEncoder().encodeToString(salt) + "$" +
               Base64.getEncoder().encodeToString(hash);
    }
}

Message Authentication Code (MAC)

Message Authentication Code

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

public class HmacService {

    public byte[] generateHmac(byte[] data, byte[] key) throws Exception {
        Mac mac = Mac.getInstance("HmacSHA256");
        SecretKeySpec secretKey = new SecretKeySpec(key, "HmacSHA256");
        mac.init(secretKey);
        return mac.doFinal(data);
    }

    public boolean verifyHmac(byte[] data, byte[] key, byte[] expectedHmac)
            throws Exception {
        byte[] actualHmac = generateHmac(data, key);
        return MessageDigest.isEqual(actualHmac, expectedHmac);  // Constant-time comparison
    }
}

// Use case: API request signing
public class ApiSigner {

    public String signRequest(String method, String path, String body,
                              String apiSecret, long timestamp) throws Exception {
        String stringToSign = method + "\n" + path + "\n" + timestamp + "\n" + body;

        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(new SecretKeySpec(apiSecret.getBytes(), "HmacSHA256"));
        byte[] signature = mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8));

        return Base64.getEncoder().encodeToString(signature);
    }
}

Key Exchange

Diffie-Hellman Key Exchange

import java.security.*;
import javax.crypto.KeyAgreement;

public class EcdhKeyExchange {

    public KeyPair generateKeyPair() throws Exception {
        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC");
        keyGen.initialize(new ECGenParameterSpec("secp256r1"));
        return keyGen.generateKeyPair();
    }

    public byte[] deriveSharedSecret(PrivateKey privateKey,
                                      PublicKey otherPublicKey) throws Exception {
        KeyAgreement keyAgreement = KeyAgreement.getInstance("ECDH");
        keyAgreement.init(privateKey);
        keyAgreement.doPhase(otherPublicKey, true);
        return keyAgreement.generateSecret();
    }

    // Derive AES key from shared secret
    public SecretKey deriveAesKey(byte[] sharedSecret) throws Exception {
        MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
        byte[] keyBytes = sha256.digest(sharedSecret);
        return new SecretKeySpec(keyBytes, "AES");
    }
}

TLS/SSL

TLS 1.3 Handshake


Certificates and PKI

Public Key Infrastructure


Random Number Generation

Cryptographic Random Numbers

import java.security.SecureRandom;

public class SecureRandomExample {

    private final SecureRandom random = new SecureRandom();

    public byte[] generateKey(int bits) {
        byte[] key = new byte[bits / 8];
        random.nextBytes(key);
        return key;
    }

    public String generateToken(int length) {
        byte[] bytes = new byte[length];
        random.nextBytes(bytes);
        return Base64.getUrlEncoder().withoutPadding().encodeToString(bytes);
    }

    public String generateOtp(int digits) {
        int max = (int) Math.pow(10, digits);
        int otp = random.nextInt(max);
        return String.format("%0" + digits + "d", otp);
    }
}

Common Interview Questions

  1. Symmetric vs Asymmetric encryption?
  2. Symmetric: Same key, fast, for bulk data
  3. Asymmetric: Key pair, slow, for key exchange/signatures

  4. Why use AES-GCM?

  5. Provides encryption + authentication
  6. Fast, parallelizable
  7. Industry standard

  8. How is HTTPS secured?

  9. TLS handshake establishes encrypted channel
  10. Certificate verifies server identity
  11. Symmetric encryption for data

  12. Why bcrypt for passwords?

  13. Intentionally slow (configurable work factor)
  14. Built-in salt
  15. Resistant to GPU attacks

  16. What is forward secrecy?

  17. Compromised long-term key doesn't reveal past sessions
  18. Each session uses ephemeral keys
  19. ECDHE provides forward secrecy

  • *