Reputation: 197
I was tasked an assignment by my teacher to make a python program that can encrypt messages using the RSA algorithm. So to do that I had to create functions which convert text to numbers and then be able to manipulate those numbers and encrypt it. However to test if i have encrypted it correctly i also designed a decryption function which I also made at the bottom. All the functions between the encryption functions and Ascii functions are there to be used in other functions(At this point you would realize i like dividing my code into functions). The problem with my code is that i keep getting this error when i run it
Traceback (most recent call last):
File "D:/Applications/Python/Ziad/RSA algotrithim V2.py", line 127, in <module>
print(decrypt(Phi_N, e, encrypted))
File "D:/Applications/Python/Ziad/RSA algotrithim V2.py", line 115, in decrypt
return Num2Text(message)
File "D:/Applications/Python/Ziad/RSA algotrithim V2.py", line 58, in Num2Text
return Ascii2Text(Num2Ascii(message))
File "D:/Applications/Python/Ziad/RSA algotrithim V2.py", line 17, in Ascii2Text
text = text + chr(int(char))
ValueError: invalid literal for int() with base 10: '1.0'
>>> ================================ RESTART =================
I tested all the functions individually to see if they work and they do. I rechecked my encryption and decryption functions and they should work. For some reason i think my problem is with my decryption function as i think it is giving me the decimal number however i searched the internet on the algorithm and all the sites i looked uses the same algorithm. Please help me with finding the problem, I usually dont ask other people for help (This is my first ever question on StackOverFlow) and I've been hurting my head on this for 3 weeks.
import math
def Text2Ascii(message):
Ascii = ""
for count in range(len(message)):
if len(str(ord(message[count]))) <= 2:
Ascii = Ascii + "0" +str(ord(message[count])) + " "
else:
Ascii = Ascii + str(ord(message[count])) + " "
return Ascii
def Ascii2Text(message):
text = ""
char = ""
for count in range(len(message)):
if message[count] == " ":
text = text + chr(int(char))
char = ""
else:
char = char + message[count]
text = text + chr(int(char))
return text
def Ascii2Num(message):
Num = ""
for count in range(len(message)):
if message[count] != " ":
Num = Num + message[count]
return int(Num)
def Num2Ascii(message):
Ascii = ""
char = ""
message = str(message)
if len(message)%3 == 0:
for count in range(len(message)):
if (count+1)%3 == 0:
char = char + message[count]
Ascii = Ascii + char + " "
char = ""
else:
char = char + message[count]
else:
Ascii = "0"
for count in range(len(message)):
if (count+2)%3 == 0:
char = char + message[count]
Ascii = Ascii + char + " "
char = ""
else:
char = char + message[count]
return Ascii
def Text2Num(message):
return Ascii2Num(Text2Ascii(message))
def Num2Text(message):
return Ascii2Text(Num2Ascii(message))
def exponent(number, power):
answer = 1
for count in range(power):
answer = number*answer
return answer
def primeCheck(number):
if number == 2:
prime = True
elif number <= 1:
prime = False
else:
n = math.sqrt(number)
n = math.ceil(n)
for count in range(2,n+1):
if number%count == 0:
prime = False
break
else:
prime = True
return prime
def factors(number):
answer = []
if primeCheck(number)== True:
answer = [number,1]
else:
for count in range(1,number+1):
if number%count == 0:
answer.append(count)
return answer
def phi(number):
answer = number
if primeCheck(number) == True:
answer = number - 1
else:
factor = factors(number)
for count in factor:
for count2 in factors(count):
if count2 == count:
answer = answer -1
break
return answer
def encrypt(N,e):
message = input("What is the message you need encrypted?\n")
message = Text2Num(message)
encrypted = (message ** e)%N
return encrypted
def decrypt(Phi_N, e,encrypted):
k = 3
d = (Phi_N*k + 1)/e
message = encrypted ** d
return Num2Text(message)
p = int(input("Give me a prime number: "))
while primeCheck(p) == False:
p = int(input("Give me a prime number: "))
q = int(input("Give me a prime number: "))
while primeCheck(q) == False:
q = int(input("Give me a prime number: "))
N = q*p
Phi_N = (q-1)*(p-1)
e = int(input("Enter your encryption key: "))
encrypted = encrypt(N,e)
print(decrypt(Phi_N, e, encrypted))
Upvotes: 1
Views: 904
Reputation: 524
That specific error that you're getting is due to combination of two factors:
The first, and probably easiest to address, is the way you are breaking up the string in Ascii2Text:
def Ascii2Text(message):
text = ""
char = ""
for count in range(len(message)):
**if message[count] == " ":** #<-- This line is not robust
text = text + chr(int(char))
char = ""
else:
char = char + message[count]
text = text + chr(int(char))
return text
The problem is that, with the way Num2Ascii is implemented, you are ending up with both a trailing space that causes you to try to cast empty string to an int at the end of the loop, and non-space characters earlier in your ascii-fied message. I would recommend either loudly choking on invalid characters, or at the very least not trying to append them to the "char" string that you try to cast to an int on the next line.
This brings us to the next problem: that you even have non-numeral characters in the first place. The decimal point causing the failure you see is coming from an incorrect calculation for d. d is supposed to be the modular multiplicative inverse of e, and it will always be an integer when calculated correctly. Yours, however, was coming up as a decimal more often than not when I ran this code. This is one of the bits of RSA that people choke on most often, since it involves manipulating the modulo operator in ways that people without a math background aren't typically taught. One of the more common, efficient ways to calculate this value is to use the Extended Euclidean algorithm.
A few more notes on things you will probably run into after addressing the two issues above:
e should be co-prime with and less than Phi_N, which you are not currently validating. Failure to do this can make it impossible to correctly calculate d (only few pairs of numbers have a modular multiplicative inverse). The easiest (though not strictly correct) way to do this would be to use a while loop beneath e like you did for the prime numbers, which checks that False == primeCheck(e) or e >= Phi_N
. To be more correct, you'd have to write a coprime check that takes in both Phi_N and e, and asserts that they do not share a common factor besides 1.
The padded version of your message, m, must be less than N. Failure to do this may result in some messages being unrecoverable when you attempt to reverse the exponentiation during decryption. To more easily verify this, you may want to capture the message from the user before they select P and Q (they're more likely to change their numbers than the message they want to send), then add an additional gate after the two primes are provided which checks that N > m.
Upvotes: 1