Projekt 1 klart praktiskt
This commit is contained in:
commit
74d60a2cb5
6 changed files with 299 additions and 0 deletions
60
src/rsa/EuclideanAlgorithm.java
Normal file
60
src/rsa/EuclideanAlgorithm.java
Normal 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
36
src/rsa/Main.java
Normal 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 ❌"));
|
||||
}
|
||||
}
|
5
src/rsa/PerformanceTest.java
Normal file
5
src/rsa/PerformanceTest.java
Normal file
|
@ -0,0 +1,5 @@
|
|||
package src.rsa;
|
||||
|
||||
public class PerformanceTest {
|
||||
|
||||
}
|
102
src/rsa/PrimeGenerator.java
Normal file
102
src/rsa/PrimeGenerator.java
Normal 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
43
src/rsa/RSAEncryptor.java
Normal 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));
|
||||
}
|
||||
|
||||
}
|
53
src/rsa/RSAKeyGenerator.java
Normal file
53
src/rsa/RSAKeyGenerator.java
Normal 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]);
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Reference in a new issue