Projekt 1 klart praktiskt

This commit is contained in:
dDogge 2025-02-14 14:12:13 +01:00
commit 74d60a2cb5
6 changed files with 299 additions and 0 deletions

View file

@ -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.");
}
}
}

36
src/rsa/Main.java Normal file
View file

@ -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 ❌"));
}
}

View file

@ -0,0 +1,5 @@
package src.rsa;
public class PerformanceTest {
}

102
src/rsa/PrimeGenerator.java Normal file
View file

@ -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! 🎉");
}
}

43
src/rsa/RSAEncryptor.java Normal file
View file

@ -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));
}
}

View file

@ -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]);
}
}