Cryptography Basics¶
Cryptography Overview¶
Symmetric Encryption¶
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)¶
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¶
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¶
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¶
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)¶
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¶
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¶
Certificates and PKI¶
Random Number Generation¶
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¶
- Symmetric vs Asymmetric encryption?
- Symmetric: Same key, fast, for bulk data
-
Asymmetric: Key pair, slow, for key exchange/signatures
-
Why use AES-GCM?
- Provides encryption + authentication
- Fast, parallelizable
-
Industry standard
-
How is HTTPS secured?
- TLS handshake establishes encrypted channel
- Certificate verifies server identity
-
Symmetric encryption for data
-
Why bcrypt for passwords?
- Intentionally slow (configurable work factor)
- Built-in salt
-
Resistant to GPU attacks
-
What is forward secrecy?
- Compromised long-term key doesn't reveal past sessions
- Each session uses ephemeral keys
- ECDHE provides forward secrecy
- *