diff --git a/README.md b/README.md index 41b167f..13da34f 100644 --- a/README.md +++ b/README.md @@ -2,33 +2,79 @@ This is my implementation of RSA cracking algorithm based on Pollard factorization. It will work if the prime number `n` as part of the public key has not a very big maximum prime factor. Of course, all modern RSA implementations don't have this security hole so this is more of an educational project that doesn't have much real-world applications. # Usage -In order to start the script, simply run `python pollard.py` +In order to start the script, simply run `python cracker.py` You will need 4 inputs: -1. `b` - the maximum prime factor of `n`. -2. `n` - prime number in the public key so that `m = c ^ d mod n` where `m` is the message, `c` is the encrypted message, `d` is the private key. +1. `n` - prime number in the public key so that `m = c ^ d mod n` where `m` is the message, `c` is the encrypted message, `d` is the private key. +2. `e` - the second public key component (so that `gcd(e, phi(n)) = 1`). 3. `c` - the encrypted message. -4. `e` - the second public key component (so that `gcd(e, phi(n)) = 1`). +4. `b` - the maximum prime factor of `n`. This field is optional. However, if you leave it blank, the brute-force algorithm will be used for factorizing `n`. # Demo ``` -Enter b (the maximum prime number factor): 200000 Enter n (as part of the public key): 186444745729857899758373984272541398503249351266417000699738642133172271283265124803102459 -Enter c (the encrypted message to decrypt): 159178142916077677757648147687519523540045276157456113470673097514775229976995968698190914 Enter e (as part of the public key): 65537 -Factorizing n to find its prime divisors... +Enter c (the encrypted message to decrypt): 159178142916077677757648147687519523540045276157456113470673097514775229976995968698190914 +Enter b (the maximum prime factor in n, optional): 200000 +Factorizing n with the Pollard algorithm... +k has 86871 digits +Trying to solve with a = 2 (a ^ k mod n) - 1 = 95072790833932492612013226959843266212858324985456485206430737027466196168851937286400160 p = 2962244945158622279601750283735698362054297 q = 62940354083336669282335053470277744418281466547 Factorizing complete. phi(n) = 186444745729857899758373984272541398503249288323100672417910737518517050721785008159581616 Solving e * d = 1 mod phi(n) with the euklidian algorithm... -a = -41924961744066952541910026492278294547238731739590378098215520069737488388039514552813743 -b = 14737 d (private key) = 144519783985790947216463957780263103956010556583510294319695217448779562333745493606767873 m (decrypted message) = 2020 ``` +# Demo with small numbers +## Brute-force +``` +Enter n (as part of the public key): 493 +Enter e (as part of the public key): 45 +Enter c (the encrypted message to decrypt): 56 +Enter b (the maximum prime factor in n, optional): +Factorizing n with the BRUTEFORCE algorithm... +p = 17 +q = 29 +Factorizing complete. +phi(n) = 448 +Solving e * d = 1 mod phi(n) with the euklidian algorithm... +d (private key) = 229 +m (decrypted message) = 490 +``` +## Pollard +``` +Enter n (as part of the public key): 493 +Enter e (as part of the public key): 45 +Enter c (the encrypted message to decrypt): 56 +Enter b (the maximum prime factor in n, optional): 493 +Factorizing n with the Pollard algorithm... +k has 216 digits +Trying to solve with a = 2 +(a ^ k mod n) - 1 = 0 +Trying to solve with a = 3 +(a ^ k mod n) - 1 = 0 +Trying to solve with a = 4 +(a ^ k mod n) - 1 = 0 + +... + +Trying to solve with a = 509 +(a ^ k mod n) - 1 = 0 +Trying to solve with a = 510 +(a ^ k mod n) - 1 = 203 +p = 29 +q = 17 +Factorizing complete. +phi(n) = 448 +Solving e * d = 1 mod phi(n) with the euklidian algorithm... +d (private key) = 229 +m (decrypted message) = 490 +``` + # Credits * Mirko Hoehn for helping me with the mathematics behind RSA. diff --git a/cracker.py b/cracker.py index 0b0bfc9..3c59e04 100644 --- a/cracker.py +++ b/cracker.py @@ -14,7 +14,7 @@ n = int(input("Enter n (as part of the public key): ")) e = int(input("Enter e (as part of the public key): ")) c = int(input("Enter c (the encrypted message to decrypt): ")) - b = int(input("Enter b (the maximum prime factor in n, optional): ") or n) + b = int(input("Enter b (the maximum prime factor in n, optional): ") or 1) # Demo: # n = 186444745729857899758373984272541398503249351266417000699738642133172271283265124803102459 @@ -24,11 +24,13 @@ p = None - if b >= n or b < 1: + if b > n or b <= 1: print("Factorizing n with the BRUTEFORCE algorithm...") p = find_factor(n) else: print("Factorizing n with the Pollard algorithm...") + if b > n - 1: + b = n - 1 p = pollard(b, n) print("p = " + str(p)) diff --git a/euklidian.py b/euklidian.py index 9ac97d0..603210d 100644 --- a/euklidian.py +++ b/euklidian.py @@ -74,5 +74,11 @@ def inverse_modulo(a, n): if b < 0: b += n - - return b \ No newline at end of file + + return b + +def next_divisor_of(d, n): + d = d + 1 + while d < n and gcd(d, n) != 1: + d = d + 1 + return d \ No newline at end of file diff --git a/pollard.py b/pollard.py index d1b26f9..a5a1488 100644 --- a/pollard.py +++ b/pollard.py @@ -7,7 +7,7 @@ from prime import nextPrime from powmod import aPowbModn -from euklidian import gcd +from euklidian import gcd, next_divisor_of def calculateK(b): @@ -28,7 +28,7 @@ def calculateK(b): maximalePrimFaktor = currentPrimFaktor currentExponent += 1 - print("Found factor in k: "+str(currentPrime)+" ^ "+str(currentExponent)+" = "+str(maximalePrimFaktor)) + # print("Found factor in k: "+str(currentPrime)+" ^ "+str(currentExponent)+" = "+str(maximalePrimFaktor)) k *= maximalePrimFaktor @@ -40,25 +40,22 @@ def pollard(b, n): k = calculateK(b) - factor = 1 - - while n % 2 == 0: - factor = factor * 2 - n = n // 2 + # print("k = " + str(k)) + print("k has " + str(len(str(k))) + " digits") + p = 1 # a is an arbitraty element in the multiplicative group of divisors of 1 modulo n - # as gcd(n-1, n) = 1 for all n, we can pick a = n - 1 - # or we can pick 2 if n is odd - a = 2 # n - 1 + a = next_divisor_of(1, n) - # print("k = " + str(k)) - print("k has " + str(len(str(k))) + " digits") - print("a = " + str(a)) + while p == 1 or p >= n: + print("Trying to solve with a = " + str(a)) + + aPowKModNminus1 = aPowbModn(a, k, n) - 1 - aPowKModNminus1 = aPowbModn(a, k, n) - 1 + print("(a ^ k mod n) - 1 = " + str(aPowKModNminus1)) - print("(a ^ k mod n) - 1 = " + str(aPowKModNminus1)) + p = gcd(aPowKModNminus1, n) - p = gcd(aPowKModNminus1, n) + a = next_divisor_of(a, n) - return factor * p \ No newline at end of file + return p \ No newline at end of file