Cybersecurity Grundlagen: Kryptographie, Verschlüsselung, Hash-Funktionen & Digitale Signaturen
Dieser Beitrag ist eine umfassende Einführung in die Cybersecurity Grundlagen – inklusive Kryptographie, Verschlüsselung, Hash-Funktionen und digitalen Signaturen mit praktischen Beispielen.
In a Nutshell
Kryptographie schützt Daten durch Verschlüsselung, Hash-Funktionen sichern Integrität und digitale Signaturen garantieren Authentizität. Moderne Security basiert auf mathematischen Algorithmen.
Kompakte Fachbeschreibung
Kryptographie ist die Wissenschaft der Verschlüsselung und Entschlüsselung von Informationen zum Schutz vor unbefugtem Zugriff.
Hauptbereiche:
Symmetrische Verschlüsselung
- Konzept: Gleicher Schlüssel für Ver- und Entschlüsselung
- Algorithmen: AES, DES, 3DES, Blowfish
- Vorteile: Schnell, effizient für große Datenmengen
- Nachteile: Schlüsselverteilung problematisch
Asymmetrische Verschlüsselung
- Konzept: Öffentlicher und privater Schlüssel
- Algorithmen: RSA, ECC, DSA, ElGamal
- Vorteile: Sichere Schlüsselverteilung
- Nachteile: Langsamer, rechenintensiv
Hash-Funktionen
- Konzept: Einweg-Funktion für digitale Fingerabdrücke
- Algorithmen: SHA-256, SHA-3, MD5 (veraltet), bcrypt
- Eigenschaften: Kollisionsresistenz, Preimage-Resistenz
- Anwendungen: Passwort-Hashing, Datenintegrität
Digitale Signaturen
- Konzept: Kryptographische Signatur für Authentizität
- Prozess: Hashing → Verschlüsseln mit Private Key
- Verifizierung: Entschlüsseln mit Public Key → Hash-Vergleich
- Standards: RSA, DSA, ECDSA
Prüfungsrelevante Stichpunkte
- Kryptographie: Wissenschaft der sicheren Kommunikation
- Symmetrische Verschlüsselung: AES, gleicher Schlüssel für beide Richtungen
- Asymmetrische Verschlüsselung: RSA, Public/Private Key-Paare
- Hash-Funktionen: SHA-256, Einweg-Hash für Integrität
- Digitale Signaturen: RSA/ECDSA, Authentizität und Integrität
- SSL/TLS: Verschlüsselte Webkommunikation
- IHK-relevant: Grundlage für IT-Sicherheit und Datenschutz
Kernkomponenten
- Verschlüsselung: Schutz der Vertraulichkeit
- Hash-Funktionen: Sicherung der Integrität
- Digitale Signaturen: Garantie der Authentizität
- Public Key Infrastructure: Schlüsselmanagement
- SSL/TLS: Sichere Netzwerkkommunikation
- Kryptografische Protokolle: Sichere Datenübertragung
- Schlüsselmanagement: Erzeugung, Speicherung, Verteilung
- Security Best Practices: Implementierung und Anwendung
Praxisbeispiele
1. Symmetrische Verschlüsselung mit AES
import javax.crypto.*;
import javax.crypto.spec.*;
import java.security.*;
import java.util.Base64;
public class SymmetricEncryptionDemo {
private static final String ALGORITHM = "AES";
private static final String TRANSFORMATION = "AES/CBC/PKCS5Padding";
private static final int KEY_LENGTH = 256;
private static final int IV_LENGTH = 16;
// AES Schlüssel generieren
public static SecretKey generateAESKey() throws NoSuchAlgorithmException {
KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM);
keyGenerator.init(KEY_LENGTH);
return keyGenerator.generateKey();
}
// Initialisierungsvektor (IV) generieren
public static byte[] generateIV() {
byte[] iv = new byte[IV_LENGTH];
new SecureRandom().nextBytes(iv);
return iv;
}
// Daten verschlüsseln
public static String encryptAES(String plaintext, SecretKey key, byte[] iv)
throws Exception {
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
IvParameterSpec ivSpec = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
byte[] encryptedBytes = cipher.doFinal(plaintext.getBytes());
// IV und verschlüsselte Daten kombinieren
byte[] combined = new byte[iv.length + encryptedBytes.length];
System.arraycopy(iv, 0, combined, 0, iv.length);
System.arraycopy(encryptedBytes, 0, combined, iv.length, encryptedBytes.length);
return Base64.getEncoder().encodeToString(combined);
}
// Daten entschlüsseln
public static String decryptAES(String ciphertext, SecretKey key) throws Exception {
byte[] combined = Base64.getDecoder().decode(ciphertext);
// IV extrahieren
byte[] iv = new byte[IV_LENGTH];
System.arraycopy(combined, 0, iv, 0, iv.length);
// Verschlüsselte Daten extrahieren
byte[] encryptedBytes = new byte[combined.length - iv.length];
System.arraycopy(combined, iv.length, encryptedBytes, 0, encryptedBytes.length);
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
IvParameterSpec ivSpec = new IvParameterSpec(iv);
cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
return new String(decryptedBytes);
}
// AES-256 Demo
public static void aesDemo() {
try {
System.out.println("=== AES-256 Verschlüsselung Demo ===");
// Schlüssel generieren
SecretKey aesKey = generateAESKey();
System.out.println("AES-256 Schlüssel generiert");
System.out.println("Schlüssel (Base64): " + Base64.getEncoder().encodeToString(aesKey.getEncoded()));
// Testdaten
String plaintext = "Dies ist eine geheime Nachricht, die mit AES-256 verschlüsselt wird.";
System.out.println("\nKlartext: " + plaintext);
// Verschlüsseln
byte[] iv = generateIV();
String ciphertext = encryptAES(plaintext, aesKey, iv);
System.out.println("\nVerschlüsselt: " + ciphertext);
// Entschlüsseln
String decryptedText = decryptAES(ciphertext, aesKey);
System.out.println("\nEntschlüsselt: " + decryptedText);
// Überprüfung
System.out.println("\nVerschlüsselung erfolgreich: " + plaintext.equals(decryptedText));
} catch (Exception e) {
System.err.println("Fehler bei AES-Verschlüsselung: " + e.getMessage());
}
}
// Performance-Vergleich verschiedener AES-Modi
public static void compareAESModes() {
try {
System.out.println("\n=== AES Modi Performance-Vergleich ===");
String[] modes = {"AES/ECB/PKCS5Padding", "AES/CBC/PKCS5Padding",
"AES/GCM/NoPadding", "AES/CFB/PKCS5Padding"};
SecretKey key = generateAESKey();
String testData = "Performance-Test-Daten für verschiedene AES-Modi. ".repeat(100);
for (String mode : modes) {
long startTime = System.nanoTime();
try {
Cipher cipher = Cipher.getInstance(mode);
if (mode.contains("ECB")) {
cipher.init(Cipher.ENCRYPT_MODE, key);
} else {
byte[] iv = generateIV();
IvParameterSpec ivSpec = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
}
byte[] encrypted = cipher.doFinal(testData.getBytes());
long endTime = System.nanoTime();
long duration = (endTime - startTime) / 1_000_000; // ms
System.out.printf("%-25s: %dms (%d bytes)%n",
mode, duration, encrypted.length);
} catch (Exception e) {
System.out.printf("%-25s: Fehler - %s%n", mode, e.getMessage());
}
}
} catch (Exception e) {
System.err.println("Fehler bei Performance-Vergleich: " + e.getMessage());
}
}
public static void main(String[] args) {
aesDemo();
compareAESModes();
}
}
2. Asymmetrische Verschlüsselung mit RSA
import javax.crypto.*;
import java.security.*;
import java.security.spec.*;
import java.util.Base64;
public class AsymmetricEncryptionDemo {
private static final String ALGORITHM = "RSA";
private static final int KEY_SIZE = 2048;
private static final String SIGNATURE_ALGORITHM = "SHA256withRSA";
// RSA Schlüsselpaar generieren
public static KeyPair generateRSAKeyPair() throws NoSuchAlgorithmException {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance(ALGORITHM);
keyGen.initialize(KEY_SIZE);
return keyGen.generateKeyPair();
}
// Mit Public Key verschlüsseln
public static String encryptRSA(String plaintext, PublicKey publicKey) throws Exception {
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptedBytes = cipher.doFinal(plaintext.getBytes());
return Base64.getEncoder().encodeToString(encryptedBytes);
}
// Mit Private Key entschlüsseln
public static String decryptRSA(String ciphertext, PrivateKey privateKey) throws Exception {
byte[] encryptedBytes = Base64.getDecoder().decode(ciphertext);
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
return new String(decryptedBytes);
}
// Digitale Signatur erstellen
public static String signData(String data, PrivateKey privateKey) throws Exception {
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
signature.initSign(privateKey);
signature.update(data.getBytes());
byte[] signatureBytes = signature.sign();
return Base64.getEncoder().encodeToString(signatureBytes);
}
// Digitale Signatur verifizieren
public static boolean verifySignature(String data, String signatureStr, PublicKey publicKey)
throws Exception {
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
signature.initVerify(publicKey);
signature.update(data.getBytes());
byte[] signatureBytes = Base64.getDecoder().decode(signatureStr);
return signature.verify(signatureBytes);
}
// RSA Demo
public static void rsaDemo() {
try {
System.out.println("=== RSA Verschlüsselung Demo ===");
// Schlüsselpaar generieren
KeyPair keyPair = generateRSAKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();
System.out.println("RSA-2048 Schlüsselpaar generiert");
System.out.println("Public Key: " + Base64.getEncoder().encodeToString(publicKey.getEncoded()));
System.out.println("Private Key: " + Base64.getEncoder().encodeToString(privateKey.getEncoded()));
// Testdaten
String plaintext = "Diese Nachricht wird mit RSA-2048 verschlüsselt und digital signiert.";
System.out.println("\nKlartext: " + plaintext);
// Verschlüsseln mit Public Key
String ciphertext = encryptRSA(plaintext, publicKey);
System.out.println("\nVerschlüsselt (Public Key): " + ciphertext);
// Entschlüsseln mit Private Key
String decryptedText = decryptRSA(ciphertext, privateKey);
System.out.println("Entschlüsselt (Private Key): " + decryptedText);
// Digitale Signatur erstellen
String signature = signData(plaintext, privateKey);
System.out.println("\nDigitale Signatur: " + signature);
// Signatur verifizieren
boolean isValid = verifySignature(plaintext, signature, publicKey);
System.out.println("Signatur gültig: " + isValid);
// Manipulierte Signatur testen
String manipulatedData = plaintext + " (manipuliert)";
boolean isManipulatedValid = verifySignature(manipulatedData, signature, publicKey);
System.out.println("Manipulierte Signatur gültig: " + isManipulatedValid);
} catch (Exception e) {
System.err.println("Fehler bei RSA-Verschlüsselung: " + e.getMessage());
}
}
// Hybrid-Verschlüsselung (RSA + AES)
public static void hybridEncryptionDemo() {
try {
System.out.println("\n=== Hybrid-Verschlüsselung Demo (RSA + AES) ===");
// Schlüssel generieren
KeyPair rsaKeyPair = generateRSAKeyPair();
SecretKey aesKey = SymmetricEncryptionDemo.generateAESKey();
// Große Datenmenge
String largeData = "Dies ist eine große Datenmenge, die mit AES verschlüsselt und der AES-Schlüssel dann mit RSA verschlüsselt wird. ".repeat(50);
System.out.println("Originaldaten Größe: " + largeData.length() + " Zeichen");
// Schritt 1: Daten mit AES verschlüsseln
byte[] iv = SymmetricEncryptionDemo.generateIV();
String encryptedData = SymmetricEncryptionDemo.encryptAES(largeData, aesKey, iv);
System.out.println("Mit AES verschlüsselt: " + encryptedData.length() + " Zeichen");
// Schritt 2: AES-Schlüssel mit RSA verschlüsseln
String encryptedKey = encryptRSA(Base64.getEncoder().encodeToString(aesKey.getEncoded()), rsaKeyPair.getPublic());
System.out.println("AES-Schlüssel mit RSA verschlüsselt");
// Schritt 3: Entschlüsselung (umgekehrt)
String decryptedKey = decryptRSA(encryptedKey, rsaKeyPair.getPrivate());
byte[] decodedKey = Base64.getDecoder().decode(decryptedKey);
SecretKey restoredAESKey = new SecretKeySpec(decodedKey, "AES");
String decryptedData = SymmetricEncryptionDemo.decryptAES(encryptedData, restoredAESKey);
System.out.println("Hybrid-Verschlüsselung erfolgreich: " + largeData.equals(decryptedData));
} catch (Exception e) {
System.err.println("Fehler bei Hybrid-Verschlüsselung: " + e.getMessage());
}
}
// RSA Key-Size Vergleich
public static void compareKeySizes() {
try {
System.out.println("\n=== RSA Key-Size Vergleich ===");
int[] keySizes = {1024, 2048, 4096};
String testData = "Testdaten für Key-Size Vergleich";
for (int keySize : keySizes) {
try {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance(ALGORITHM);
keyGen.initialize(keySize);
KeyPair keyPair = keyGen.generateKeyPair();
long startTime = System.nanoTime();
String encrypted = encryptRSA(testData, keyPair.getPublic());
long encryptTime = System.nanoTime() - startTime;
startTime = System.nanoTime();
String decrypted = decryptRSA(encrypted, keyPair.getPrivate());
long decryptTime = System.nanoTime() - startTime;
System.out.printf("RSA-%d: Verschlüsselung %dms, Entschlüsselung %dms%n",
keySize, encryptTime / 1_000_000, decryptTime / 1_000_000);
} catch (Exception e) {
System.out.printf("RSA-%d: Fehler - %s%n", keySize, e.getMessage());
}
}
} catch (Exception e) {
System.err.println("Fehler bei Key-Size Vergleich: " + e.getMessage());
}
}
public static void main(String[] args) {
rsaDemo();
hybridEncryptionDemo();
compareKeySizes();
}
}
3. Hash-Funktionen und Passwort-Sicherheit
import java.security.*;
import java.util.Base64;
import javax.crypto.*;
import javax.crypto.spec.*;
import java.util.Arrays;
public class HashFunctionsDemo {
private static final String SHA_256 = "SHA-256";
private static final String SHA_3_256 = "SHA3-256";
private static final String BCRYPT = "BCrypt";
// SHA-256 Hash berechnen
public static String sha256(String input) throws NoSuchAlgorithmException {
MessageDigest digest = MessageDigest.getInstance(SHA_256);
byte[] hashBytes = digest.digest(input.getBytes());
return Base64.getEncoder().encodeToString(hashBytes);
}
// SHA-3 Hash berechnen
public static String sha3_256(String input) throws NoSuchAlgorithmException {
MessageDigest digest = MessageDigest.getInstance(SHA_3_256);
byte[] hashBytes = digest.digest(input.getBytes());
return Base64.getEncoder().encodeToString(hashBytes);
}
// Salted Hash (mit zufälligem Salt)
public static String saltedHash(String password, byte[] salt) throws NoSuchAlgorithmException {
MessageDigest digest = MessageDigest.getInstance(SHA_256);
digest.reset();
digest.update(salt);
byte[] hashBytes = digest.digest(password.getBytes());
return Base64.getEncoder().encodeToString(hashBytes);
}
// Salt generieren
public static byte[] generateSalt() {
byte[] salt = new byte[16];
new SecureRandom().nextBytes(salt);
return salt;
}
// PBKDF2 für Passwort-Hashing
public static String pbkdf2Hash(String password, byte[] salt, int iterations, int keyLength)
throws NoSuchAlgorithmException, InvalidKeySpecException {
PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, iterations, keyLength);
SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
byte[] hash = skf.generateSecret(spec).getEncoded();
return Base64.getEncoder().encodeToString(hash);
}
// Passwort mit PBKDF2 verifizieren
public static boolean verifyPassword(String password, String storedHash, byte[] salt, int iterations)
throws NoSuchAlgorithmException, InvalidKeySpecException {
String newHash = pbkdf2Hash(password, salt, iterations, storedHash.length());
return newHash.equals(storedHash);
}
// HMAC für Message Authentication
public static String hmacSHA256(String data, String secretKey) throws Exception {
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(), "HmacSHA256");
mac.init(secretKeySpec);
byte[] hmacBytes = mac.doFinal(data.getBytes());
return Base64.getEncoder().encodeToString(hmacBytes);
}
// Hash-Kollisionstest
public static void testHashCollisions() {
try {
System.out.println("=== Hash-Kollisionstest ===");
String[] testStrings = {
"password123",
"password124", // Sehr ähnlich
"Password123", // Groß/Kleinschreibung
"pass word123", // Leerzeichen
"pa$$word123" // Sonderzeichen
};
System.out.println("SHA-256 Hashes:");
for (String test : testStrings) {
String hash = sha256(test);
System.out.printf("%-15s: %s%n", test, hash);
}
System.out.println("\nSHA-3 Hashes:");
for (String test : testStrings) {
String hash = sha3_256(test);
System.out.printf("%-15s: %s%n", test, hash);
}
} catch (Exception e) {
System.err.println("Fehler bei Kollisionstest: " + e.getMessage());
}
}
// Passwort-Sicherheits-Demo
public static void passwordSecurityDemo() {
try {
System.out.println("\n=== Passwort-Sicherheits-Demo ===");
String password = "MySecurePassword123!";
// 1. Einfacher Hash (unsicher)
String simpleHash = sha256(password);
System.out.println("Einfacher SHA-256: " + simpleHash);
// 2. Salted Hash
byte[] salt = generateSalt();
String saltedHashStr = saltedHash(password, salt);
System.out.println("Salted Hash: " + saltedHashStr);
System.out.println("Salt: " + Base64.getEncoder().encodeToString(salt));
// 3. PBKDF2 (empfohlen)
int iterations = 10000;
int keyLength = 256;
String pbkdf2HashStr = pbkdf2Hash(password, salt, iterations, keyLength);
System.out.println("PBKDF2 Hash: " + pbkdf2HashStr);
System.out.println("Iterationen: " + iterations);
// 4. Verifikation
boolean isValid = verifyPassword(password, pbkdf2HashStr, salt, iterations);
System.out.println("Passwort gültig: " + isValid);
// 5. Timing Attack Protection
System.out.println("\nTiming Attack Protection Test:");
testTimingAttackProtection();
} catch (Exception e) {
System.err.println("Fehler bei Passwort-Sicherheit: " + e.getMessage());
}
}
// Timing Attack Protection Demo
public static void testTimingAttackProtection() {
try {
String correctPassword = "correctPassword123";
String wrongPassword = "wrongPassword456";
byte[] salt = generateSalt();
String storedHash = pbkdf2Hash(correctPassword, salt, 10000, 256);
// Timing Tests
long[] correctTimes = new long[10];
long[] wrongTimes = new long[10];
for (int i = 0; i < 10; i++) {
// Korrektes Passwort
long start = System.nanoTime();
verifyPassword(correctPassword, storedHash, salt, 10000);
correctTimes[i] = System.nanoTime() - start;
// Falsches Passwort
start = System.nanoTime();
verifyPassword(wrongPassword, storedHash, salt, 10000);
wrongTimes[i] = System.nanoTime() - start;
}
long avgCorrect = Arrays.stream(correctTimes).sum() / correctTimes.length;
long avgWrong = Arrays.stream(wrongTimes).sum() / wrongTimes.length;
System.out.printf("Korrektes Passwort: %dms (Durchschnitt)%n", avgCorrect / 1_000_000);
System.out.printf("Falsches Passwort: %dms (Durchschnitt)%n", avgWrong / 1_000_000);
System.out.printf("Timing-Differenz: %.2f%%n",
Math.abs(avgCorrect - avgWrong) * 100.0 / Math.max(avgCorrect, avgWrong));
} catch (Exception e) {
System.err.println("Fehler bei Timing Attack Test: " + e.getMessage());
}
}
// HMAC Demo
public static void hmacDemo() {
try {
System.out.println("\n=== HMAC Demo ===");
String message = "Dies ist eine vertrauliche Nachricht";
String secretKey = "geheimerSchlüssel123";
// HMAC berechnen
String hmac = hmacSHA256(message, secretKey);
System.out.println("Nachricht: " + message);
System.out.println("HMAC: " + hmac);
// HMAC mit falschem Schlüssel
String wrongKey = "falscherSchlüssel456";
String wrongHmac = hmacSHA256(message, wrongKey);
System.out.println("HMAC (falscher Key): " + wrongHmac);
// Verifikation
boolean isValid = hmac.equals(hmacSHA256(message, secretKey));
boolean isInvalid = !wrongHmac.equals(hmacSHA256(message, secretKey));
System.out.println("HMAC gültig: " + isValid);
System.out.println("Falscher HMAC erkannt: " + isInvalid);
} catch (Exception e) {
System.err.println("Fehler bei HMAC Demo: " + e.getMessage());
}
}
public static void main(String[] args) {
testHashCollisions();
passwordSecurityDemo();
hmacDemo();
}
}
4. SSL/TLS und Zertifikate
import javax.net.ssl.*;
import java.io.*;
import java.net.*;
import java.security.*;
import java.security.cert.*;
import java.util.Base64;
public class SSLTLSDemo {
// SSL-Kontext erstellen
public static SSLContext createSSLContext() throws Exception {
// Trust Manager (für Server-Zertifikate)
TrustManager[] trustManagers = new TrustManager[] {
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType) {
// In Produktion: Zertifikat validieren
System.out.println("Server-Zertifikat validiert");
}
}
};
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagers, new SecureRandom());
return sslContext;
}
// HTTPS-Request mit SSL
public static void makeHTTPSRequest(String urlString) {
try {
System.out.println("=== HTTPS Request Demo ===");
URL url = new URL(urlString);
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
// SSL-Kontext setzen
SSLContext sslContext = createSSLContext();
connection.setSSLSocketFactory(sslContext.getSocketFactory());
// Hostname Verifier (für Demo)
connection.setHostnameVerifier((hostname, session) -> {
System.out.println("Hostname: " + hostname);
return true; // In Produktion: proper hostname verification
});
connection.setRequestMethod("GET");
connection.setConnectTimeout(10000);
connection.setReadTimeout(10000);
int responseCode = connection.getResponseCode();
System.out.println("Response Code: " + responseCode);
// Zertifikatsinformationen
Certificate[] certs = connection.getServerCertificates();
if (certs.length > 0 && certs[0] instanceof java.security.cert.X509Certificate) {
java.security.cert.X509Certificate cert = (java.security.cert.X509Certificate) certs[0];
System.out.println("Server-Zertifikat:");
System.out.println(" Subject: " + cert.getSubjectDN());
System.out.println(" Issuer: " + cert.getIssuerDN());
System.out.println(" Valid from: " + cert.getNotBefore());
System.out.println(" Valid until: " + cert.getNotAfter());
System.out.println(" Serial Number: " + cert.getSerialNumber());
}
// TLS-Version
System.out.println("TLS Protocol: " + connection.getSSLSession().getProtocol());
System.out.println("Cipher Suite: " + connection.getSSLSession().getCipherSuite());
// Antwort lesen
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(connection.getInputStream()))) {
String line;
StringBuilder response = new StringBuilder();
while ((line = reader.readLine()) != null) {
response.append(line).append("\n");
}
System.out.println("Response (first 200 chars):");
System.out.println(response.substring(0, Math.min(200, response.length())));
}
} catch (Exception e) {
System.err.println("Fehler bei HTTPS Request: " + e.getMessage());
}
}
// Selbstsigniertes Zertifikat erstellen
public static void generateSelfSignedCertificate() {
try {
System.out.println("\n=== Selbstsigniertes Zertifikat Demo ===");
// KeyPair generieren
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048);
KeyPair keyPair = keyGen.generateKeyPair();
// Zertifikat erstellen (vereinfacht)
// In der Praxis würde man BouncyCastle oder ähnliche Libraries verwenden
System.out.println("KeyPair generiert für selbstsigniertes Zertifikat");
System.out.println("Public Key: " + Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded()));
} catch (Exception e) {
System.err.println("Fehler bei Zertifikatserstellung: " + e.getMessage());
}
}
// Cipher Suites auflisten
public static void listCipherSuites() {
try {
System.out.println("\n=== Unterstützte Cipher Suites ===");
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, null, null);
String[] cipherSuites = sslContext.getServerSocketFactory().getSupportedCipherSuites();
System.out.println("Anzahl unterstützter Cipher Suites: " + cipherSuites.length);
System.out.println("\nEmpfohlene Cipher Suites:");
for (String suite : cipherSuites) {
// Nur moderne, sichere Cipher Suites anzeigen
if (suite.contains("TLS_ECDHE") && suite.contains("GCM")) {
System.out.println(" " + suite);
}
}
} catch (Exception e) {
System.err.println("Fehler bei Cipher Suite Auflistung: " + e.getMessage());
}
}
// SSL-Handshake analysieren
public static void analyzeSSLHandshake() {
try {
System.out.println("\n=== SSL Handshake Analyse ===");
SSLContext sslContext = createSSLContext();
// Custom SSL Parameters
SSLParameters sslParams = new SSLParameters();
sslParams.setEndpointIdentificationAlgorithm("HTTPS");
sslParams.setProtocols(new String[]{"TLSv1.3", "TLSv1.2"});
// Sichere Cipher Suites
String[] secureSuites = {
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256"
};
sslParams.setCipherSuites(secureSuites);
System.out.println("SSL Konfiguration:");
System.out.println(" Protokolle: " + String.join(", ", sslParams.getProtocols()));
System.out.println(" Cipher Suites: " + sslParams.getCipherSuites().length + " konfiguriert");
System.out.println(" Hostname Verification: " + sslParams.getEndpointIdentificationAlgorithm());
} catch (Exception e) {
System.err.println("Fehler bei SSL Analyse: " + e.getMessage());
}
}
// Certificate Chain Validation
public static void validateCertificateChain() {
try {
System.out.println("\n=== Certificate Chain Validation ===");
// Beispiel für Certificate Path Validation
CertificateFactory cf = CertificateFactory.getInstance("X.509");
// In der Praxis würde man die Zertifikate aus einer Datei laden
// Hier zeigen wir nur die Konzepte
System.out.println("Certificate Path Validation Konzepte:");
System.out.println("1. Root CA Certificate");
System.out.println("2. Intermediate CA Certificate(s)");
System.out.println("3. End Entity Certificate");
System.out.println("4. Certificate Revocation Check (CRL/OCSP)");
System.out.println("5. Certificate Transparency Logs");
// Trust Manager Konfiguration
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
// KeyStore für vertrauenswürdige Zertifikate
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null); // Leerer TrustStore
// In Produktion: System-TrustStore laden oder eigene Zertifikate hinzufügen
// trustStore.load(new FileInputStream("truststore.jks"), "password".toCharArray());
tmf.init(trustStore);
TrustManager[] trustManagers = tmf.getTrustManagers();
System.out.println("Trust Manager konfiguriert: " + trustManagers.length + " Manager");
} catch (Exception e) {
System.err.println("Fehler bei Certificate Validation: " + e.getMessage());
}
}
public static void main(String[] args) {
// HTTPS Request Demo
// makeHTTPSRequest("https://www.google.com");
// Zertifikat-Demos
generateSelfSignedCertificate();
listCipherSuites();
analyzeSSLHandshake();
validateCertificateChain();
}
}
Kryptographie-Algorithmen Übersicht
Symmetrische Algorithmen
| Algorithmus | Schlüssellänge | Blockgröße | Anwendung | Sicherheit |
|---|---|---|---|---|
| AES | 128/192/256 | 128 Bit | Standard | Sicher |
| DES | 56 | 64 | Veraltet | Unsicher |
| 3DES | 168 | 64 | Legacy | Schwach |
| Blowfish | 32-448 | 64 | Verschiedene | Sicher |
Asymmetrische Algorithmen
| Algorithmus | Schlüssellänge | Anwendung | Sicherheit | Performance |
|---|---|---|---|---|
| RSA | 1024-4096 | Signatur/Verschlüsselung | Sicher | Langsam |
| ECC | 160-521 | Signatur/Verschlüsselung | Sicher | Schnell |
| DSA | 1024-3072 | Signatur | Sicher | Langsam |
| ElGamal | 1024-4096 | Verschlüsselung | Sicher | Langsam |
Hash-Algorithmen
| Algorithmus | Ausgabelänge | Kollisionssicherheit | Status | Anwendung |
|---|---|---|---|---|
| SHA-256 | 256 Bit | Sicher | Empfohlen | Allzweck |
| SHA-3 | 224-512 | Sicher | Modern | Allzweck |
| MD5 | 128 Bit | Gebrochen | Veraltet | Prüfsummen |
| bcrypt | Variable | Sicher | Empfohlen | Passwörter |
SSL/TLS Protokoll-Versionen
| Version | Jahr | Sicherheit | Cipher Suites | Empfehlung |
|---|---|---|---|---|
| SSL 2.0 | 1995 | Unsicher | Veraltet | Nicht verwenden |
| SSL 3.0 | 1996 | Unsicher | Veraltet | Nicht verwenden |
| TLS 1.0 | 1999 | Schwach | Begrenzt | Nicht verwenden |
| TLS 1.1 | 2006 | OK | Begrenzt | Nicht verwenden |
| TLS 1.2 | 2008 | Sicher | Modern | Empfohlen |
| TLS 1.3 | 2018 | Sehr Sicher | Modern | Beste Wahl |
Passwort-Sicherheit Best Practices
Hashing-Methoden
// ❌ Unsicher
String hash = md5(password);
// ⚠️ Besser
String hash = sha256(password);
// ✅ Sicher
String hash = pbkdf2(password, salt, 100000);
// ✅ Am besten
String hash = bcrypt(password);
Salting
// Salt generieren
byte[] salt = generateSalt(); // 16+ Bytes zufällig
// Salt speichern (nicht geheim)
String saltedHash = salt + ":" + hash(password, salt);
Key Derivation
// PBKDF2 Parameter
int iterations = 100000; // Mindestens 100.000
int keyLength = 256; // 256 Bit
int saltLength = 32; // 32 Bytes
String derivedKey = pbkdf2(password, salt, iterations, keyLength);
Digitale Signaturen Prozess
Signatur-Erstellung
- Hash berechnen:
hash = SHA256(data) - Hash verschlüsseln:
signature = RSA_encrypt(hash, private_key) - Signatur anhängen:
data + signature
Signatur-Verifizierung
- Signatur extrahieren:
signature = extract(data_with_signature) - Hash berechnen:
hash = SHA256(data) - Signatur entschlüsseln:
decrypted_hash = RSA_decrypt(signature, public_key) - Vergleichen:
hash == decrypted_hash ?
Public Key Infrastructure (PKI)
Komponenten
- Root CA: Vertrauenswürdige Stammzertifizierungsstelle
- Intermediate CA: Zwischenzertifizierungsstellen
- End Entity: Server/Client-Zertifikate
- CRL: Certificate Revocation List
- OCSP: Online Certificate Status Protocol
Zertifikats-Validierung
// 1. Certificate Chain prüfen
// 2. Ablaufdatum prüfen
// 3. Revocation prüfen (CRL/OCSP)
// 4. Hostname prüfen
// 5. Signatur prüfen
Security Best Practices
Implementation
// ✅ Sichere Konfiguration
SSLContext sslContext = SSLContext.getInstance("TLSv1.3");
sslContext.init(null, trustManagers, null);
// ✅ Sichere Cipher Suites
String[] secureSuites = {
"TLS_AES_256_GCM_SHA384",
"TLS_CHACHA20_POLY1305_SHA256",
"TLS_AES_128_GCM_SHA256"
};
// ✅ Hostname Verification
connection.setHostnameVerifier((hostname, session) -> {
return hostname.equals(session.getPeerHost());
});
Fehlervermeidung
// ❌ Falsch: TrustManager deaktivieren
TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() { /* alle Zertifikate akzeptieren */ }
};
// ✅ Richtig: Eigene TrustManager mit Validierung
TrustManager[] secureTrustManagers = new TrustManager[] {
new X509TrustManager() {
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
// Eigene Validierungslogik
}
}
};
Vorteile und Nachteile
Vorteile von Kryptographie
- Vertraulichkeit: Schutz vor unbefugtem Zugriff
- Integrität: Erkennung von Datenmanipulation
- Authentizität: Verifizierung der Identität
- Non-Repudiation: Nichtanfechtbarkeit
- Compliance: Erfüllung von Sicherheitsstandards
Nachteile
- Komplexität: Fachwissen erforderlich
- Performance: Rechenintensive Operationen
- Key Management: Schlüsselverwaltung aufwändig
- Overhead: Zusätzliche Infrastruktur
Häufige Prüfungsfragen
-
Was ist der Unterschied zwischen symmetrischer und asymmetrischer Verschlüsselung? Symmetrisch verwendet einen Schlüssel für beide Richtungen, asymmetrisch verwendet Public/Private Key-Paare.
-
Warum sind Salted Hashes für Passwörter wichtig? Salts verhindern Rainbow-Table-Angriffe und sorgen für einzigartige Hashes auch bei gleichen Passwörtern.
-
Erklären Sie digitale Signaturen! Digitale Signaturen verwenden Hashing und asymmetrische Verschlüsselung um Authentizität und Integrität zu garantieren.
-
Was ist der Zweck von SSL/TLS? SSL/TLS sichert die Kommunikation im Internet durch Verschlüsselung und Authentifizierung.
Wichtigste Quellen
- https://docs.oracle.com/javase/8/docs/technotes/guides/security/crypto/CryptoSpec.html
- https://www.ietf.org/rfc/rfc5246.html (TLS 1.2)
- https://www.ietf.org/rfc/rfc8446.html (TLS 1.3)