Modern Cryptography and Public Key Infrastructure (Criptografia Moderna e Infraestrutura de Chaves Públicas)¶
This section covers modern cryptographic techniques that form the backbone of internet security, including asymmetric encryption, digital signatures, key exchange protocols, and public key infrastructure. These concepts are essential for understanding how secure communications work on the web.
Overview¶
Modern cryptography addresses limitations of classical methods by solving the fundamental problem: how to securely communicate when you have no pre-existing shared secret. This is achieved through mathematical problems that are easy to compute in one direction but computationally infeasible to reverse.
Key Concepts Covered¶
- Asymmetric Encryption: Using key pairs (public/private) for secure communication
- Digital Signatures: Ensuring authenticity and non-repudiation
- Key Exchange Protocols: Securely establishing shared secrets over insecure channels
- Public Key Infrastructure (PKI): Managing digital certificates and trust
Mathematical Foundations¶
The Discrete Logarithm Problem¶
Given a prime $p$, a generator $g$, and value $y = g^x \mod p$, finding $x$ given $(p, g, y)$ is computationally difficult. This forms the basis of: - Diffie-Hellman Key Exchange - ElGamal Encryption
The Integer Factorization Problem¶
Given a large composite number $n = p \times q$ (where $p, q$ are primes), finding $p$ and $q$ is difficult. This forms the basis of: - RSA Encryption
Elliptic Curve Discrete Logarithm Problem¶
Finding $k$ given points $P$ and $Q = kP$ on an elliptic curve is computationally hard, even for relatively small key sizes. This enables: - ECC (Elliptic Curve Cryptography) - smaller keys with equivalent security to RSA
Asymmetric Encryption (Criptografia Assimétrica)¶
Asymmetric encryption uses a pair of mathematically related keys: - Public Key: Can be shared openly, used for encryption or signature verification - Private Key: Must be kept secret, used for decryption or signing
RSA (Rivest-Shamir-Adleman)¶
RSA is based on the difficulty of factoring large integers.
Mathematical Foundation¶
Given: - Two large prime numbers $p$ and $q$ - Modulus $n = p \times q$ - Euler's totient function $\phi(n) = (p-1)(q-1)$ - Public exponent $e$ (typically 65537, coprime to $\phi(n)$) - Private exponent $d$ such that $ed \equiv 1 \mod \phi(n)$
Encryption: $C = M^e \mod n$
Decryption: $M = C^d \mod n$
Java Implementation¶
import java.math.BigInteger;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
public class RSAEncryption {
private static final int KEY_SIZE = 2048;
/**
* Generates a new RSA key pair.
*/
public static KeyPair generateKeyPair() throws Exception {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(KEY_SIZE);
return keyGen.generateKeyPair();
}
/**
* Encrypts data using the recipient's public key.
*/
public static byte[] encrypt(byte[] plaintext, PublicKey publicKey) throws Exception {
java.security.spec.EncryptedPrivateKeyInfo enc =
new java.security.spec.EncryptedPrivateKeyInfo(publicKey.getEncoded());
// For RSA encryption, use Cipher class instead
javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(javax.crypto.Cipher.ENCRYPT_MODE, publicKey);
return cipher.doFinal(plaintext);
}
/**
* Decrypts data using the private key.
*/
public static byte[] decrypt(byte[] ciphertext, PrivateKey privateKey) throws Exception {
javax.crypto.Cipher cipher = javax.crypto.Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(javax.crypto.Cipher.DECRYPT_MODE, privateKey);
return cipher.doFinal(ciphertext);
}
public static void main(String[] args) throws Exception {
KeyPair keyPair = generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
String message = "Secret message";
// Encrypt with public key
byte[] encrypted = encrypt(message.getBytes(), publicKey);
System.out.println("Encrypted length: " + encrypted.length);
// Decrypt with private key
String decrypted = new String(decrypt(encrypted, privateKey));
System.out.println("Decrypted: " + decrypted);
}
}
Elliptic Curve Cryptography (ECC)¶
ECC provides equivalent security to RSA with much smaller keys.
| Security Level | RSA Key Size | ECC Key Size |
|---|---|---|
| 128-bit | 3072 bits | 256 bits |
| 192-bit | 7680 bits | 384 bits |
| 256-bit | 15360 bits | 512 bits |
ECDSA (Elliptic Curve Digital Signature Algorithm)¶
ECDSA is used for digital signatures and provides the same security as RSA with smaller keys.
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public class ECDSASignature {
static {
Security.addProvider(new BouncyCastleProvider());
}
public static void main(String[] args) throws Exception {
// Generate key pair
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC", "BC");
keyGen.initialize(256);
KeyPair keyPair = keyGen.generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
// Sign data
byte[] message = "Message to sign".getBytes();
java.security.Signature signature =
java.security.Signature.getInstance("SHA256withECDSA", "BC");
signature.initSign(privateKey);
signature.update(message);
byte[] signatureBytes = signature.sign();
// Verify signature
signature.initVerify(publicKey);
signature.update(message);
boolean isValid = signature.verify(signatureBytes);
System.out.println("Signature valid: " + isValid);
}
}
Digital Signatures (Assinaturas Digitais)¶
Digital signatures provide three security guarantees: 1. Authenticity: The message was signed by the claimed sender 2. Integrity: The message has not been modified 3. Non-repudiation: The signer cannot deny having signed it
How Digital Signatures Work¶
Signing Process:
1. Hash the message: h = H(M)
2. Encrypt hash with private key: s = D_priv(h)
(This is the signature)
Verification Process:
1. Hash received message: h' = H(M')
2. Decrypt signature with public key: h'' = E_pub(s)
3. Compare: if h' == h'', signature is valid
RSA Digital Signature Implementation¶
import java.security.*;
import java.util.Base64;
public class DigitalSignature {
/**
* Signs a message using the private key.
*/
public static String signMessage(byte[] message, PrivateKey privateKey) throws Exception {
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initSign(privateKey);
signature.update(message);
byte[] signatureBytes = signature.sign();
return Base64.getEncoder().encodeToString(signatureBytes);
}
/**
* Verifies a message signature using the public key.
*/
public static boolean verifySignature(byte[] message, String base64Signature, PublicKey publicKey) throws Exception {
Signature signature = Signature.getInstance("SHA256withRSA");
signature.initVerify(publicKey);
signature.update(message);
byte[] signatureBytes = Base64.getDecoder().decode(base64Signature);
return signature.verify(signatureBytes);
}
public static void main(String[] args) throws Exception {
KeyPair keyPair = RSAEncryption.generateKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();
String message = "Important document content";
// Sign the message
String signature = signMessage(message.getBytes(), privateKey);
System.out.println("Signature: " + signature);
// Verify the signature
boolean isValid = verifySignature(message.getBytes(), signature, publicKey);
System.out.println("Verification passed: " + isValid);
}
}
Key Exchange Protocols (Protocolos de Troca de Chaves)¶
Diffie-Hellman Key Exchange¶
Diffie-Hellman allows two parties to establish a shared secret over an insecure channel without having exchanged any secret information beforehand.
Mathematical Foundation¶
Given: - A large prime $p$ - A generator $g$ (typically 2 or 3)
Alice: 1. Choose private key $a$ randomly 2. Compute public value $A = g^a \mod p$ 3. Send $A$ to Bob
Bob: 1. Choose private key $b$ randomly 2. Compute public value $B = g^b \mod p$ 3. Send $B$ to Alice
Shared Secret: Both compute $s = B^a \mod p = A^b \mod p$
Java Implementation¶
import java.math.BigInteger;
import java.security.SecureRandom;
public class DiffieHellman {
// Standard parameters (RFC 7919)
private static final BigInteger P = new BigInteger("FFFFFFFFFFFFFFFFC90FDAA2" +
"2168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A087" +
"98E3404DDEF9519B3CD3A431B302B026038C13ACFFFFFFFBCFC6EE1BBC7FF59" +
"B88BB9BCB09CBECECDD4EBA3EDBD4547B9280CD73CDA250F164C406CBBA290" +
"5F47E52BDF9D8EFF2A30E1F7BB4CC89B68F15D42A58ED30ABDDA62FFCF4F90" +
"3EBC965FFC9BFD859AC479CA81E99A3ED9B6D1FE609731A", 16);
private static final BigInteger G = new BigInteger("2");
/**
* Generates a Diffie-Hellman key pair.
*/
public static KeyPair generateKeyPair() {
SecureRandom random = new SecureRandom();
// Generate private key (1024 bits)
byte[] privateKeyBytes = new byte[128];
random.nextBytes(privateKeyBytes);
BigInteger privateKey = new BigInteger(1, privateKeyBytes);
// Ensure private key is in valid range [2, P-2]
while (privateKey.compareTo(BigInteger.ONE) <= 0 ||
privateKey.compareTo(P.subtract(BigInteger.ONE)) >= 0) {
random.nextBytes(privateKeyBytes);
privateKey = new BigInteger(1, privateKeyBytes);
}
// Compute public key: Y = g^x mod p
BigInteger publicKey = G.modPow(privateKey, P);
return new KeyPair(publicKey, privateKey);
}
/**
* Computes shared secret from peer's public key.
*/
public static byte[] computeSharedSecret(BigInteger theirPublicKey, PrivateKey myPrivateKey) {
// Shared secret: s = Y^x mod p
BigInteger sharedSecret = theirPublicKey.modPow(myPrivateKey, P);
// Hash the result to get a usable key
java.security.MessageDigest digest;
try {
digest = java.security.MessageDigest.getInstance("SHA-256");
} catch (Exception e) {
throw new RuntimeException(e);
}
return digest.digest(sharedSecret.toByteArray());
}
public static void main(String[] args) throws Exception {
// Alice generates key pair
KeyPair aliceKeyPair = generateKeyPair();
BigInteger alicePublic = (BigInteger) aliceKeyPair.getPublic();
PrivateKey alicePrivate = (PrivateKey) aliceKeyPair.getPrivate();
// Bob generates key pair
KeyPair bobKeyPair = generateKeyPair();
BigInteger bobPublic = (BigInteger) bobKeyPair.getPublic();
PrivateKey bobPrivate = (PrivateKey) bobKeyPair.getPrivate();
// Alice computes shared secret using Bob's public key
byte[] aliceSecret = computeSharedSecret(bobPublic, alicePrivate);
// Bob computes shared secret using Alice's public key
byte[] bobSecret = computeSharedSecret(alicePublic, bobPrivate);
System.out.println("Alice and Bob have the same shared secret: " +
java.util.Arrays.equals(aliceSecret, bobSecret));
}
}
Ephemeral Diffie-Hellman (DHE) and Elliptic Curve DH (ECDH)¶
Modern implementations use ephemeral keys for forward secrecy:
- DHE: Uses temporary Diffie-Hellman keys that are discarded after key exchange
- ECDHE: Uses elliptic curve variants, providing better performance
These ensure that even if long-term private keys are compromised, past communications remain secure.
Public Key Infrastructure (PKI)¶
Digital Certificates¶
A digital certificate binds a public key to an identity and is signed by a Certificate Authority (CA).
Certificate Structure (X.509)¶
Certificate ::= SEQUENCE {
tbsCertificate TBSCertificate,
signatureAlgorithm AlgorithmIdentifier,
signatureValue BIT STRING
}
TBSCertificate ::= SEQUENCE {
version [0] EXPLICIT Version DEFAULT v1,
serialNumber CertificateSerialNumber,
signature AlgorithmIdentifier,
issuer Name,
validity Validity,
subject Name,
subjectPublicKeyInfo SubjectPublicKeyInfo,
...
}
Java PKI Implementation¶
import java.security.*;
import java.util.Date;
public class CertificateManagement {
/**
* Creates a self-signed certificate (for testing only).
*/
public static X509Certificate createSelfSignedCertificate(PrivateKey privateKey, String cn)
throws Exception {
// Create certificate builder
X509V3CertificateBuilder builder = new X509V3CertificateBuilder(
new GeneralName(Name.buildCN(cn)), // Issuer
new Date(System.currentTimeMillis()), // Not before
new Date(System.currentTimeMillis() + 365 * 24 * 60 * 60 * 1000), // Not after (1 year)
new GeneralName(Name.buildCN(cn)), // Subject
privateKey.getPublicKey(), // Public key
"SHA-256" // Signature algorithm
);
// Generate and sign certificate
JcaX509v3CertificateBuilder jcaBuilder = new JcaX509v3CertificateBuilder(
builder, privateKey);
ContentSigner signer = new JcaContentSignerBuilder("SHA256WithRSAEncryption")
.setProvider("BC").build(privateKey);
return jcaBuilder.build(signer, privateKey);
}
/**
* Verifies a certificate chain.
*/
public static boolean verifyCertificateChain(X509Certificate[] chain) throws Exception {
X509Certificate leaf = chain[0];
// Verify signature of each certificate in the chain
for (int i = 1; i < chain.length; i++) {
X509Certificate issuer = chain[i];
X509Certificate subject = chain[i - 1];
PublicKey publicKey = issuer.getPublicKey();
java.security.cert.Certificate cert = subject;
// Verify that the issuer signed the subject's certificate
if (!issuer.verify(cert.getEncoded())) {
return false;
}
}
// Verify leaf certificate signature
return leaf.verify(leaf.getIssuerPublicKey());
}
}
Certificate Authority (CA) Hierarchy¶
PKI uses a hierarchical trust model:
Root CA (Self-signed, trusted by browsers/OS)
└── Intermediate CA 1 (Signed by Root CA)
├── Intermediate CA 2 (Signed by IC1)
│ └── Server Certificate (Signed by IC2)
└── Server Certificate (Signed by IC1)
└── Server Certificate (Signed by Root CA)
Using Java's TrustStore¶
import java.security.KeyStore;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
public class SSLClient {
public static void main(String[] args) throws Exception {
// Load truststore (contains trusted CA certificates)
KeyStore trustStore = KeyStore.getInstance("JKS");
try (InputStream is = new FileInputStream("/path/to/truststore.jks")) {
trustStore.load(is, "password".toCharArray());
}
// Initialize TrustManagerFactory
TrustManagerFactory tmf = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustStore);
// Create SSLContext
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
// Use for HTTPS connections
HttpsURLConnection connection = (HttpsURLConnection) new URL("https://example.com").openConnection();
connection.setSSLSocketFactory(sslContext.getSocketFactory());
}
}
TLS/SSL Protocol¶
TLS (Transport Layer Security) is the protocol that secures web communications. It combines:
- Key Exchange: ECDHE for forward secrecy
- Authentication: Server certificate verification
- Encryption: AES-GCM or ChaCha20-Poly1305
- Integrity: AEAD (Authenticated Encryption with Associated Data)
TLS Handshake Overview¶
Client Hello: Client proposes cipher suites, compression methods
Server Hello: Server selects cipher suite, sends certificate
Certificate Verify: Client verifies server's certificate
Key Exchange: Both parties compute shared secret using ECDHE
Finished Messages: Both parties verify the handshake was successful
Application Data: Encrypted communication begins
Security Considerations¶
Best Practices¶
- Use strong algorithms: AES-256-GCM, RSA 4096+, ECC P-384 or higher
- Avoid deprecated algorithms: MD5, SHA-1, RC4, DES, 3DES
- Enable forward secrecy: Use ECDHE instead of RSA key exchange
- Use TLS 1.3: Provides better security and performance than TLS 1.2
- Implement certificate pinning for mobile applications
Common Vulnerabilities¶
| Vulnerability | Description | Mitigation |
|---|---|---|
| Heartbleed | Memory disclosure in OpenSSL | Update libraries, regenerate keys |
| POODLE | Padding oracle attack on SSL 3.0 | Disable SSL 3.0, use TLS |
| BEAST | Browser security update attack | Use AES-GCM or ChaCha20 |
| FREAK | Forcing RSA downgrade to export ciphers | Disable export ciphers |
References¶
- RFC 6478: Elliptic Curve Diffie-Hellman (ECDH) Key Agreement Protocol
- RFC 5280: Internet X.509 Public Key Infrastructure Certificate Profile
- RFC 8446: The Transport Layer Security (TLS) Protocol Version 1.3
- Menezes, A. J., van Oorschot, P. C., & Vanstone, S. A. (1996). Handbook of Applied Cryptography. CRC Press.
- Bernstein, D. J., Lange, T., & Schwabe, P. (2017). "Post-Quantum Cryptography".