initial commit
This commit is contained in:
commit
12127e5873
9
.gitignore
vendored
Normal file
9
.gitignore
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
### IntelliJ IDEA ###
|
||||||
|
out/
|
||||||
|
/.idea/
|
||||||
|
|
||||||
|
!out/artifacts/fermat_rsa_attack_jar
|
||||||
|
!**/src/main/**/out/
|
||||||
|
!**/src/test/**/out/
|
||||||
|
|
||||||
|
fermat_rsa_attack.iml
|
30
README.md
Normal file
30
README.md
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
# Fermat Attack on RSA
|
||||||
|
|
||||||
|
This is just a little ugly program to
|
||||||
|
attack on RSA modul with an approach of Fermat.
|
||||||
|
|
||||||
|
Use: `java -jar fermat_rsa_attack.jar [MODUL] [TRIES]`
|
||||||
|
|
||||||
|
where MODUL is the RSA-modul (generated from both keys you want to evaluate)
|
||||||
|
and TRIES the amount of iterations to avoid long runtime.
|
||||||
|
TRIES is optional. If not given the default amount of trie is 100.
|
||||||
|
If there is no solution found within the tries then give a bigger number up to
|
||||||
|
approx. 2 billion (integer 32).
|
||||||
|
|
||||||
|
---
|
||||||
|
The modul `N` evaluates from product of two prime numbers (except 2):
|
||||||
|
`N = p1 * p2`
|
||||||
|
|
||||||
|
For the two prime numbers exists `a` and `b` with `p1 = a-b` and `p2 = a+b`.
|
||||||
|
So `N` can be evaluated as `N = (a-b)(a+b) = a^2 - b^2`.
|
||||||
|
|
||||||
|
The number `a` must lie in between `p1` and `p2` with equal distance `b`.
|
||||||
|
A good guess for such an `a` is the square root of `N` as a starting point.
|
||||||
|
In each iteration increase `a` by 1 until a solution is found or the amount of tries is exhausted.
|
||||||
|
|
||||||
|
In the iteration itself calculate `b^2 = a^2 - N` then check if `b` is non-negative and a square number.
|
||||||
|
If so the solution is found. If not then increase `a` by 1 and try again.
|
||||||
|
---
|
||||||
|
**This method to calculate `p1` and `p2` for RSA-keys is a good method if the two prime numbers
|
||||||
|
are close together. However, if they are not close it takes long.
|
||||||
|
So RSA with good key generators are still strong.**
|
BIN
out/artifacts/fermat_rsa_attack_jar/fermat_rsa_attack.jar
Normal file
BIN
out/artifacts/fermat_rsa_attack_jar/fermat_rsa_attack.jar
Normal file
Binary file not shown.
109
src/FermatRSAAttack.java
Normal file
109
src/FermatRSAAttack.java
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
import java.math.BigInteger;
|
||||||
|
|
||||||
|
public class FermatRSAAttack
|
||||||
|
{
|
||||||
|
private final BigInteger MODUL;
|
||||||
|
|
||||||
|
private int iterationsCount;
|
||||||
|
|
||||||
|
public FermatRSAAttack(final long rsaModul)
|
||||||
|
{
|
||||||
|
this(BigInteger.valueOf(rsaModul));
|
||||||
|
}
|
||||||
|
|
||||||
|
public FermatRSAAttack(final BigInteger rsaModul)
|
||||||
|
{
|
||||||
|
if (isNegative(rsaModul))
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("The provided RSA-Modul must be non-negative!");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.MODUL = rsaModul;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The modul {@code N} evaluates from product of two prime numbers (except 2):
|
||||||
|
* {@code N = p1 * p2}
|
||||||
|
* <br /><br />
|
||||||
|
* For the two prime numbers exists {@code a} and {@code b} with {@code p1 = a-b} and {@code p2 = a+b}.
|
||||||
|
* So {@code N} can be evaluated as {@code N = (a-b)(a+b) = a^2 - b^2}.
|
||||||
|
* <br /><br />
|
||||||
|
* The number {@code a} must lie in between {@code p1} and {@code p2} with equal distance {@code b}.
|
||||||
|
* A good guess for such an {@code a} is the square root of {@code N} as a starting point.
|
||||||
|
* In each iteration increase {@code a} by 1 until a solution is found or the amount of tries is exhausted.
|
||||||
|
* <br /><br />
|
||||||
|
* In the iteration itself calculate {@code b^2 = a^2 - N} then check if {@code b} is non-negative and a square number.
|
||||||
|
* If so the solution is found. If not then increase {@code a} by 1 and try again.
|
||||||
|
* <br /><br />
|
||||||
|
* This method to calculate {@code p1} and {@code p2} for RSA-keys is a good method if the two prime numbers
|
||||||
|
* are close together. However, if they are not close it takes long.
|
||||||
|
* So RSA with good key generators are still strong.
|
||||||
|
*
|
||||||
|
* @param tries the amount of iterations the method should trey before stop to avoid long duration
|
||||||
|
* @return a {@link KeyPair} with both prime numbers which generated the modul.
|
||||||
|
*/
|
||||||
|
public KeyPair attack(final int tries)
|
||||||
|
{
|
||||||
|
final var possibleA = this.MODUL.sqrt().add(BigInteger.ONE);
|
||||||
|
|
||||||
|
for (var i = 0; i < tries; i++)
|
||||||
|
{
|
||||||
|
final var refinement = BigInteger.valueOf(i);
|
||||||
|
|
||||||
|
final var aSquared = possibleA.add(refinement).pow(2);
|
||||||
|
final var bSquared = aSquared.subtract(this.MODUL);
|
||||||
|
|
||||||
|
if (!isNegative(bSquared) && isSquareNumber(bSquared))
|
||||||
|
{
|
||||||
|
this.iterationsCount = ++i;
|
||||||
|
|
||||||
|
final var a = aSquared.sqrt();
|
||||||
|
final var b = bSquared.sqrt();
|
||||||
|
|
||||||
|
return new KeyPair(a.subtract(b), a.add(b));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new OutOfTriesException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIterationsCount()
|
||||||
|
{
|
||||||
|
return this.iterationsCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BigInteger getMODUL()
|
||||||
|
{
|
||||||
|
return MODUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isSquareNumber(final BigInteger number)
|
||||||
|
{
|
||||||
|
return number.sqrt().pow(2).equals(number);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isNegative(final BigInteger number)
|
||||||
|
{
|
||||||
|
return number.compareTo(BigInteger.ZERO) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public record KeyPair(BigInteger p1, BigInteger p2)
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return "p1 = %d, p2 = %d".formatted(p1, p2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class OutOfTriesException extends IndexOutOfBoundsException
|
||||||
|
{
|
||||||
|
public OutOfTriesException()
|
||||||
|
{
|
||||||
|
super("""
|
||||||
|
Your given amount of tries are too few to fully compute the solution.
|
||||||
|
Iterations given and needed: %d"""
|
||||||
|
.formatted(getIterationsCount()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
3
src/META-INF/MANIFEST.MF
Normal file
3
src/META-INF/MANIFEST.MF
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
Manifest-Version: 1.0
|
||||||
|
Main-Class: Main
|
||||||
|
|
26
src/Main.java
Normal file
26
src/Main.java
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import java.math.BigInteger;
|
||||||
|
|
||||||
|
public class Main
|
||||||
|
{
|
||||||
|
public static void main(final String[] args)
|
||||||
|
{
|
||||||
|
final var key = BigInteger.valueOf(Long.parseLong(args[0]));
|
||||||
|
var tries = 100;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
tries = Integer.parseInt(args[1]);
|
||||||
|
}
|
||||||
|
catch (Exception ignored)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
final var fermatRSAAttack = new FermatRSAAttack(key);
|
||||||
|
final var primes = fermatRSAAttack.attack(tries);
|
||||||
|
|
||||||
|
System.out.printf("""
|
||||||
|
Key-pair to given MODUL %d: %s
|
||||||
|
Evaluated in %d tries.
|
||||||
|
""".formatted(fermatRSAAttack.getMODUL(), primes, fermatRSAAttack.getIterationsCount()));
|
||||||
|
}
|
||||||
|
}
|
64
test/FermatRSAAttackTest.java
Normal file
64
test/FermatRSAAttackTest.java
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
import org.junit.jupiter.api.*;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
public class FermatRSAAttackTest
|
||||||
|
{
|
||||||
|
@Test
|
||||||
|
public void testExpectExceptionForNegativeNumber()
|
||||||
|
{
|
||||||
|
assertThrows(IllegalArgumentException.class, () -> new FermatRSAAttack(BigInteger.valueOf(-1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testObjectCorrectInitialized()
|
||||||
|
{
|
||||||
|
final var actual = assertDoesNotThrow(() -> new FermatRSAAttack(BigInteger.valueOf(2)));
|
||||||
|
|
||||||
|
final var expectedModul = BigInteger.valueOf(2);
|
||||||
|
final var expectedIterationsCount = 0;
|
||||||
|
|
||||||
|
assertEquals(expectedModul, actual.getMODUL());
|
||||||
|
assertEquals(expectedIterationsCount, actual.getIterationsCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testObjectCorrectInitializedWithLong()
|
||||||
|
{
|
||||||
|
final var actual = assertDoesNotThrow(() -> new FermatRSAAttack(2));
|
||||||
|
|
||||||
|
final var expectedKey = BigInteger.valueOf(2);
|
||||||
|
final var expectedIterationsCount = 0;
|
||||||
|
|
||||||
|
assertEquals(expectedKey, actual.getMODUL());
|
||||||
|
assertEquals(expectedIterationsCount, actual.getIterationsCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFermatRSAAttack()
|
||||||
|
{
|
||||||
|
final var expectedP1 = 3;
|
||||||
|
final var expectedP2 = 5;
|
||||||
|
final var expectedIterationsCount = 1;
|
||||||
|
|
||||||
|
final var modul = expectedP1 * expectedP2;
|
||||||
|
|
||||||
|
final var fermatRSAAttack = new FermatRSAAttack(modul);
|
||||||
|
final var actualPrimes = fermatRSAAttack.attack(1_000_000);
|
||||||
|
|
||||||
|
assertEquals(expectedP1, actualPrimes.p1().longValue());
|
||||||
|
assertEquals(expectedP2, actualPrimes.p2().longValue());
|
||||||
|
assertEquals(expectedIterationsCount, fermatRSAAttack.getIterationsCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFermatRSAAttackWithTooFewTries()
|
||||||
|
{
|
||||||
|
assertThrows(FermatRSAAttack.OutOfTriesException.class, () -> {
|
||||||
|
final var fermatRSAAttack = new FermatRSAAttack(10);
|
||||||
|
fermatRSAAttack.attack(1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user