commit 74d60a2cb545d2a0915bd3a97ed47453f608950b Author: dDogge Date: Fri Feb 14 14:12:13 2025 +0100 Projekt 1 klart praktiskt diff --git a/src/rsa/EuclideanAlgorithm.java b/src/rsa/EuclideanAlgorithm.java new file mode 100644 index 0000000..30af72e --- /dev/null +++ b/src/rsa/EuclideanAlgorithm.java @@ -0,0 +1,60 @@ +package src.rsa; + +import java.math.BigInteger; + +public class EuclideanAlgorithm { + + public static BigInteger modularInverse(BigInteger a, BigInteger m) { + BigInteger m0 = m, t, q; + BigInteger x0 = BigInteger.ZERO, x1 = BigInteger.ONE; + + if (m.equals(BigInteger.ONE)) return BigInteger.ZERO; // Ingen invers om m = 1 + + while (a.compareTo(BigInteger.ONE) > 0) { + q = a.divide(m); // Kvoten + t = m; + + // m = a % m, liknar Euklides algoritm + m = a.mod(m); + a = t; + t = x0; + + // Uppdatera x0 och x1 + x0 = x1.subtract(q.multiply(x0)); + x1 = t; + } + + // Hantera negativa x1 + if (x1.compareTo(BigInteger.ZERO) < 0) { + x1 = x1.add(m0); + } + + return x1; + } + + public static BigInteger gcd(BigInteger a, BigInteger b) { + if (b.equals(BigInteger.ZERO)) { + return a; + } else { + return gcd(b, a.mod(b)); + } + } + + // 3️⃣ Testa algoritmen med några stora tal + public static void main(String[] args) { + System.out.println("=== Test av modular invers ==="); + + BigInteger a = new BigInteger("65537"); // Typiskt RSA e = 2^16 + 1 + BigInteger m = new BigInteger("973157123091"); // Slumpmässigt stort tal + + // Kontrollera om invers finns + if (gcd(a, m).equals(BigInteger.ONE)) { + BigInteger inv = modularInverse(a, m); + System.out.println("Modulär invers av " + a + " mod " + m + " är: " + inv); + // Kontroll: Ska ge 1 → (a * inv) % m == 1 + System.out.println("Verifiering: (" + a + " * " + inv + ") mod " + m + " = " + a.multiply(inv).mod(m)); + } else { + System.out.println("Ingen invers existerar för a mod m."); + } + } +} diff --git a/src/rsa/Main.java b/src/rsa/Main.java new file mode 100644 index 0000000..7dd31ea --- /dev/null +++ b/src/rsa/Main.java @@ -0,0 +1,36 @@ +package src.rsa; + +import java.math.BigInteger; +import java.util.Random; + +public class Main { + public static void main(String[] args) { + System.out.println("=== Startar RSA-programmet ==="); + + // 1️⃣ Generera RSA-nycklar + int bitLength = 512; + RSAKeyGenerator rsa = new RSAKeyGenerator(bitLength); + BigInteger[] publicKey = rsa.getPublicKey(); + BigInteger[] privateKey = rsa.getPrivateKey(); + + System.out.println("\n--- Genererade nycklar ---"); + System.out.println("Publik nyckel: N = " + publicKey[0] + ", e = " + publicKey[1]); + System.out.println("Privat nyckel: N = " + privateKey[0] + ", d = " + privateKey[1]); + + // 2️⃣ Skapa ett slumpmässigt meddelande som är mindre än N + BigInteger message = new BigInteger(bitLength - 1, new Random()); + System.out.println("\nOriginal meddelande: " + message); + + // 3️⃣ Kryptera meddelandet + BigInteger ciphertext = RSAEncryptor.encrypt(message, publicKey); + System.out.println("Krypterat meddelande: " + ciphertext); + + // 4️⃣ Dekryptera meddelandet + BigInteger decrypted = RSAEncryptor.decrypt(ciphertext, privateKey); + System.out.println("Dekrypterat meddelande: " + decrypted); + + // 5️⃣ Verifiera att dekrypteringen fungerar + boolean isCorrect = message.equals(decrypted); + System.out.println("\nStämmer dekrypteringen? " + (isCorrect ? "JA! ✅" : "NEJ ❌")); + } +} diff --git a/src/rsa/PerformanceTest.java b/src/rsa/PerformanceTest.java new file mode 100644 index 0000000..c2a573b --- /dev/null +++ b/src/rsa/PerformanceTest.java @@ -0,0 +1,5 @@ +package src.rsa; + +public class PerformanceTest { + +} diff --git a/src/rsa/PrimeGenerator.java b/src/rsa/PrimeGenerator.java new file mode 100644 index 0000000..fbba7ce --- /dev/null +++ b/src/rsa/PrimeGenerator.java @@ -0,0 +1,102 @@ +package src.rsa; + +import java.math.BigInteger; +import java.security.SecureRandom; + +public class PrimeGenerator { + private static final SecureRandom random = new SecureRandom(); + + // 1️⃣ Implementera Rabin-Miller primtalstest + public static boolean isPrime(BigInteger n, int k) { + if (n.equals(BigInteger.ONE) || n.mod(BigInteger.TWO).equals(BigInteger.ZERO)) { + return false; // 1 eller jämna tal är inte primtal (förutom 2) + } + + // Skriv n-1 som 2^r * s, där s är udda + BigInteger s = n.subtract(BigInteger.ONE); + int r = 0; + while (s.mod(BigInteger.TWO).equals(BigInteger.ZERO)) { + s = s.divide(BigInteger.TWO); + r++; + } + + // Kör testet k gånger med slumpmässiga baser + for (int i = 0; i < k; i++) { + BigInteger a = uniformRandom(BigInteger.TWO, n.subtract(BigInteger.ONE)); // Slumpmässig bas + BigInteger x = a.modPow(s, n); + + if (x.equals(BigInteger.ONE) || x.equals(n.subtract(BigInteger.ONE))) { + continue; // Möjligt primtal + } + + boolean isComposite = true; + for (int j = 0; j < r - 1; j++) { + x = x.modPow(BigInteger.TWO, n); + if (x.equals(n.subtract(BigInteger.ONE))) { + isComposite = false; + break; + } + } + + if (isComposite) { + return false; // n är sammansatt + } + } + + return true; // n är möjligen primtal + } + + // Hjälpmetod för att generera ett slumpmässigt BigInteger mellan min och max + private static BigInteger uniformRandom(BigInteger min, BigInteger max) { + BigInteger result; + do { + result = new BigInteger(max.bitLength(), random); + } while (result.compareTo(min) < 0 || result.compareTo(max) > 0); + return result; + } + + // 2️⃣ Generera ett primtal med angiven bitstorlek + public static BigInteger generatePrime(int bitLength) { + BigInteger prime; + do { + prime = new BigInteger(bitLength, random).setBit(0); // Se till att det är udda + } while (!isPrime(prime, 20)); // Testa med 20 iterationer av Rabin-Miller + return prime; + } + + // 3️⃣ Generera 100 primtal av viss storlek och mät tiden + public static void benchmarkPrimes(int bitLength) { + long startTime = System.nanoTime(); + + for (int i = 0; i < 100; i++) { + generatePrime(bitLength); + } + + long endTime = System.nanoTime(); + double elapsedTime = (endTime - startTime) / 1_000_000_000.0; // Konvertera till sekunder + System.out.println("Bitlängd: " + bitLength + " | Tid: " + elapsedTime + " sekunder"); + } + + public static void main(String[] args) { + System.out.println("=== Benchmark: Primtalsgenerering ==="); + System.out.println("| Bitlängd | Antal | Tid (ms) |"); + System.out.println("|----------|-------|----------|"); + + int[] bitSizes = {512, 1024, 2048, 4096}; // Bitstorlekar att testa + for (int bitSize : bitSizes) { + long startTime = System.currentTimeMillis(); // Starta tidtagning + + for (int i = 0; i < 100; i++) { + generatePrime(bitSize); // Generera primtal + } + + long endTime = System.currentTimeMillis(); // Sluta tidtagning + long elapsedTime = endTime - startTime; // Total tid i ms + + // Skriv ut tabellrad + System.out.printf("| %8d | %4d | %8d |\n", bitSize, 100, elapsedTime); + } + + System.out.println("\nBenchmark färdig! 🎉"); + } +} diff --git a/src/rsa/RSAEncryptor.java b/src/rsa/RSAEncryptor.java new file mode 100644 index 0000000..930ac02 --- /dev/null +++ b/src/rsa/RSAEncryptor.java @@ -0,0 +1,43 @@ +package src.rsa; + +import java.math.BigInteger; + +public class RSAEncryptor { + + public static BigInteger encrypt(BigInteger message, BigInteger[] publicKey) { + BigInteger N = publicKey[0]; + BigInteger e = publicKey[1]; + return message.modPow(e, N); // Effektiv modular exponentiation + } + + public static BigInteger decrypt(BigInteger ciphertext, BigInteger[] privateKey) { + BigInteger N = privateKey[0]; + BigInteger d = privateKey[1]; + return ciphertext.modPow(d, N); // Effektiv modular exponentiation + } + + public static void main(String[] args) { + System.out.println("=== Test av RSA Kryptering/Dekryptering ==="); + + // 1️⃣ Generera RSA-nycklar + RSAKeyGenerator rsa = new RSAKeyGenerator(512); + BigInteger[] publicKey = rsa.getPublicKey(); + BigInteger[] privateKey = rsa.getPrivateKey(); + + // 2️⃣ Slumpmässigt meddelande att kryptera + BigInteger message = new BigInteger("123456789"); + System.out.println("Original meddelande: " + message); + + // 3️⃣ Kryptera meddelandet + BigInteger ciphertext = encrypt(message, publicKey); + System.out.println("Krypterat meddelande: " + ciphertext); + + // 4️⃣ Dekryptera meddelandet + BigInteger decrypted = decrypt(ciphertext, privateKey); + System.out.println("Dekrypterat meddelande: " + decrypted); + + // 5️⃣ Verifiera att dekrypteringen är korrekt + System.out.println("Stämmer dekrypteringen? " + message.equals(decrypted)); + } + +} \ No newline at end of file diff --git a/src/rsa/RSAKeyGenerator.java b/src/rsa/RSAKeyGenerator.java new file mode 100644 index 0000000..040858a --- /dev/null +++ b/src/rsa/RSAKeyGenerator.java @@ -0,0 +1,53 @@ +package src.rsa; + +import java.math.BigInteger; + +public class RSAKeyGenerator { + private BigInteger p, q, N, e, d; + + // 1️⃣ Konstruktor: Generera nycklar + public RSAKeyGenerator(int bitLength) { + generateKeys(bitLength); + } + + private void generateKeys(int bitLength) { + System.out.println("Genererar RSA-nycklar med " + bitLength + "-bitars primtal..."); + + // 1️⃣ Generera stora primtal p och q + p = PrimeGenerator.generatePrime(bitLength); + q = PrimeGenerator.generatePrime(bitLength); + + // 2️⃣ Beräkna N = p * q + N = p.multiply(q); + + // 3️⃣ Beräkna Euler φ(N) = (p-1) * (q-1) + BigInteger phi = (p.subtract(BigInteger.ONE)).multiply(q.subtract(BigInteger.ONE)); + + // 4️⃣ Välj publik exponent e (standard är 65537) + e = new BigInteger("65537"); + + // 5️⃣ Beräkna privat exponent d = e⁻¹ mod φ(N) med utökade Euklides algoritm + d = EuclideanAlgorithm.modularInverse(e, phi); + + System.out.println("Nycklar genererade!"); + } + + + public BigInteger[] getPublicKey() { + return new BigInteger[]{N, e}; + } + + public BigInteger[] getPrivateKey() { + return new BigInteger[]{N, d}; + } + + + public static void main(String[] args) { + RSAKeyGenerator rsa = new RSAKeyGenerator(512); + + System.out.println("\n=== RSA Nycklar ==="); + System.out.println("Public Key: N = " + rsa.getPublicKey()[0] + ", e = " + rsa.getPublicKey()[1]); + System.out.println("Private Key: N = " + rsa.getPrivateKey()[0] + ", d = " + rsa.getPrivateKey()[1]); + } + +}