RSA code: Difference between revisions
Content added Content deleted
(Added Visual Basic.NET version, translation from C#) |
|||
Line 1,051: | Line 1,051: | ||
=={{header|Python}}== |
=={{header|Python}}== |
||
{{Needs-review}} |
|||
This code will open up a simple Tkinter window which has space to type a message. That message can then be encrypted by pressing the button labeled "encrypt". It will then print an output of ciphertext |
|||
blocks, separated by commas. To decrypt a message, simply press the decrypt button. All ciphertext data must be entered with each block separated by commas. The ciphertext always goes (and appears) |
|||
in the bottom box, while plaintext goes (and appears) in the topmost box. Upon decryption, random letters may have been appended to the end of the message, this is an aspect of the code to ensure the final |
|||
block of plaintext is not a single letter, for example, a, 01, encoded is 01 (which means this letter was transmitted in the open!). |
|||
<lang python>import binascii |
|||
Note: the key given here is a toy key, it is easily broken. |
|||
<lang python>from tkinter import * |
|||
import random |
|||
import time |
|||
n = 9516311845790656153499716760847001433441357 # p*q = modulus |
|||
letter = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q", |
|||
e = 65537 |
|||
"r","s","t","u","v","w","x","y","z",",",".","!","?",' '] |
|||
d = 5617843187844953170308463622230283376298685 |
|||
number = ["01","02","03","04","05","06","07","08","09","10","11","12","13", |
|||
"14","15","16","17","18","19","20","21","22","23","24","25","26","27", |
|||
"28","29","30",'31'] |
|||
print('public key ', n, e) |
|||
n = 2537 |
|||
print('private key ', n, d, '\n') |
|||
e = 13 |
|||
d = 937 |
|||
def decrypt(F,d): |
|||
# performs the decryption function on an block of ciphertext |
|||
if d == 0: |
|||
return 1 |
|||
if d == 1: |
|||
return F |
|||
w,r = divmod(d,2) |
|||
if r == 1: |
|||
return decrypt(F*F%n,w)*F%n |
|||
else: |
|||
return decrypt(F*F%n,w) |
|||
def correct(): |
|||
# Checks to see if the numerical ciphertext block should have started with a 0 (by seeing if the 0 is missing), if it is, it then adds the 0. |
|||
# example - 0102 is output as 102, which would lead the computer to think the first letter is 10, not 01. This ensures this does not happen. |
|||
for i in range(len(D)): |
|||
if len(str(P[i]))%2 !=0: |
|||
y = str(0)+str(P[i]) |
|||
P.remove(str(P[i])) |
|||
P.insert(i,y) |
|||
message='Rosetta Code!' |
|||
def cipher(b,e): |
|||
print('message ', message) |
|||
# Performs the Encryption function on a block of ciphertext |
|||
if e == 0: |
|||
return 1 |
|||
if e == 1: |
|||
return b |
|||
w,r = divmod(e,2) |
|||
if r == 1: |
|||
return cipher(b*b%n,w)*b%n |
|||
else: |
|||
return cipher(b*b%n,w) |
|||
def group(j,h,z): |
|||
# Places the plaintext numbers into blocks for encryption |
|||
for i in range(int(j)): |
|||
y = 0 |
|||
for n in range(h): |
|||
y += int(numP[(h*i)+n])*(10**(z-2*n)) |
|||
X.append(int(y)) |
|||
hex_data = binascii.hexlify(message.encode()) |
|||
print('hex data ', hex_data) |
|||
plain_text = int(hex_data, 16) |
|||
print('plain text integer ', plain_text) |
|||
if plain_text > n: |
|||
class App: |
|||
raise('plain text too large for key') |
|||
# Creates a Tkineter window, for ease of operation |
|||
def __init__(self, master): |
|||
encrypted_text = pow(plain_text, e, n) |
|||
frame = Frame(master) |
|||
print('encrypted text integer ', encrypted_text) |
|||
frame.grid() |
|||
decrypted_text = pow(encrypted_text, d, n) |
|||
#create a button with the quit command, and tell it where to go |
|||
print('decrypted text integer ', decrypted_text) |
|||
quitbutton = Button(frame, text = "quit", fg ="red", |
|||
command = root.quit, width = 10) |
|||
quitbutton.grid(row = 0, column =3) |
|||
print('message ', binascii.unhexlify(hex(decrypted_text)[2:]).decode()) # [2:] slicing, to strip the 0x part |
|||
#create an entry box, tell it where it goes, and how large it is |
|||
entry = Entry(frame, width = 100) |
|||
entry.grid(row = 0, column = 0) |
|||
</lang> |
|||
#set initial content of the entry box |
|||
self.contents = StringVar() |
|||
self.contents.set("Type message here") |
|||
entry["textvariable"] = self.contents |
|||
# Create a button which initializes the decryption of ciphertext |
|||
decrypt = Button(frame,text = "Decrypt", fg = "blue", |
|||
command = self.Decrypt) |
|||
decrypt.grid(row = 2, column = 1) |
|||
#create a label to display the number of ciphertext blocks in an encoded message |
|||
label = Label(frame, text = "# of blocks") |
|||
label.grid(row = 1, column = 1) |
|||
#creates a button which initializes the encryption of plaintext |
|||
encrypt = Button(frame, text="Encrypt", fg = "blue", |
|||
command = self.Encrypt) |
|||
encrypt.grid(row =0, column =1) |
|||
#create an entry box for the value of "n" |
|||
nbox = Entry(frame, width = 100) |
|||
nbox.grid(row = 3, column = 0) |
|||
self.n = StringVar() |
|||
self.n.set(n) |
|||
nbox["textvar"] = self.n |
|||
nbox.bind('<Key-Return>', self.set_n) #key binding, when you press "return", the value of "n" is changed to the value now in the box |
|||
nlabel = Label(frame, text = "the value of 'n'") |
|||
nlabel.grid(row = 3, column = 1) |
|||
#create an entry box for the value of "e" |
|||
ebox = Entry(frame, width = 100) |
|||
ebox.grid(row = 4, column = 0) |
|||
self.e = StringVar() |
|||
self.e.set(e) |
|||
ebox["textvar"] = self.e |
|||
ebox.bind('<Key-Return>', self.set_e) |
|||
elabel = Label(frame, text = "the value of 'e'") |
|||
elabel.grid(row = 4, column = 1) |
|||
#create an entry box for the value of "d" |
|||
dbox = Entry(frame, width = 100) |
|||
dbox.grid(row =5, column = 0) |
|||
self.d = StringVar() |
|||
self.d.set(d) |
|||
dbox["textvar"] = self.d |
|||
dbox.bind('<Key-Return>', self.set_d) |
|||
dlabel = Label(frame, text = "the value of 'd'") |
|||
dlabel.grid(row = 5, column =1) |
|||
blocks = Label(frame, width = 100) |
|||
blocks.grid(row = 1, column =0) |
|||
self.block = StringVar() |
|||
self.block.set("number of blocks") |
|||
blocks["textvar"] = self.block |
|||
output = Entry(frame, width = 100) |
|||
output.grid(row = 2, column = 0) |
|||
self.answer = StringVar() |
|||
self.answer.set("Ciphertext") |
|||
output["textvar"] = self.answer |
|||
# The commands of all the buttons are defined below |
|||
def set_n(self,event): |
|||
global n |
|||
n = int(self.n.get()) |
|||
print("n set to", n) |
|||
def set_e(self, event): |
|||
global e |
|||
e = int(self.e.get()) |
|||
print("e set to",e) |
|||
def set_d(self,event): |
|||
global d |
|||
d = int(self.d.get()) |
|||
print("d set to", d) |
|||
def Decrypt(self): |
|||
#decrypts an encoded message |
|||
global m,P,D,x,h,p,Text,y,w,PText |
|||
P = [] |
|||
D = str(self.answer.get()) #Pulls the ciphertext out of the ciphertext box |
|||
D = D.lstrip('[') #removes the bracket "[" from the left side of the string |
|||
D = D.rstrip(']') |
|||
D = D.split(',') #splits the string into a list of strings, separating at each comma. |
|||
for i in range(len(D)): #decrypts each block in the list of strings "D" |
|||
x = decrypt(int(D[i]),d) |
|||
P.append(str(x)) |
|||
correct() #ensures each block is not missing a 0 at the start |
|||
h = len(P[0]) |
|||
p = [] |
|||
for i in range(len(D)): #further separates the list P into individual characters, i.e. "0104" becomes "01,04" |
|||
for n in range(int(h/2)): |
|||
p.append(str(P[i][(2*n):((2*n)+2)])) # grabs every 2 character group from the larger block. It gets characters between 2*n, and (2*n)+2, i.e. characters 0,1 then 2,3 etc... |
|||
Text = [] |
|||
for i in range(len(p)): # converts each block back to text characters |
|||
for j in range(len(letter)): |
|||
if str(p[i]) == number[j]: |
|||
Text.append(letter[j]) |
|||
PText = str() |
|||
for i in range(len(Text)): #places all text characters in one string |
|||
PText = PText + str(Text[i]) |
|||
self.contents.set(str(PText)) #places the decrypted plaintext in the plaintext box |
|||
def Encrypt(self): |
|||
#encrypts a plaintext message using the current key |
|||
global plaintext,numP,q,j,z,X,C |
|||
plaintext = self.contents.get() #pulls the plaintext out of the entry box for use |
|||
plaintext = plaintext.lower() #places all plaintext in lower case |
|||
numP = [] |
|||
for i in range(len(plaintext)): # converts letters and symbols to their numerical values |
|||
for j in range(len(letter)): |
|||
if plaintext[i] == letter[j]: |
|||
numP.append(number[j]) |
|||
h = (len(str(n))//2)-1 # This sets the block length for the code in question, based on the value of "n" |
|||
q = len(numP)%h |
|||
for i in range(h-q): |
|||
numP.append(number[random.randint(0,25)]) # Ensures the final block of plaintext is filled with letters, and is not a single orphaned letter. |
|||
j = len(numP) / h |
|||
X = [] |
|||
z = 0 |
|||
for m in range(h-1): |
|||
z+=2 |
|||
group(j,h,z) # This sets the numerical plaintext into blocks of appropriate size, and places them in the list "X" |
|||
k = len(X) |
|||
C = [] |
|||
for i in range(k): # performs the cipher function for each block in the list of plaintext blocks |
|||
b = X[i] |
|||
r = cipher(b,e) |
|||
C.append(r) |
|||
self.answer.set(C) |
|||
self.block.set(len(C)) #places the ciphertext into the ciphertext box |
|||
root = Tk() |
|||
app = App(root) |
|||
root.mainloop() |
|||
root.destroy()</lang> |
|||
Alternatively, a version without the tkinter window, which uses the same components as the program above, only without the Tkinter interface. |
|||
<lang python>import random |
|||
import time |
|||
def decrypt(F,d): |
|||
if d == 0: |
|||
return 1 |
|||
if d == 1: |
|||
return F |
|||
w,r = divmod(d,2) |
|||
if r == 1: |
|||
return decrypt(F*F%n,w)*F%n |
|||
else: |
|||
return decrypt(F*F%n,w) |
|||
def correct(): |
|||
for i in range(len(C)): |
|||
if len(str(P[i]))%2 !=0: |
|||
y = str(0)+str(P[i]) |
|||
P.remove(str(P[i])) |
|||
P.insert(i,y) |
|||
def cipher(b,e): |
|||
if e == 0: |
|||
return 1 |
|||
if e == 1: |
|||
return b |
|||
w,r = divmod(e,2) |
|||
if r == 1: |
|||
return cipher(b*b%n,w)*b%n |
|||
else: |
|||
return cipher(b*b%n,w) |
|||
def group(j,h,z): |
|||
for i in range(int(j)): |
|||
y = 0 |
|||
for n in range(h): |
|||
y += int(numP[(h*i)+n])*(10**(z-2*n)) |
|||
X.append(int(y)) |
|||
def gcd(a, b): |
|||
while b != 0: |
|||
(a, b) = (b, a%b) |
|||
return a |
|||
letter = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q", |
|||
"r","s","t","u","v","w","x","y","z",",",".","!","?"," "] |
|||
number = ["01","02","03","04","05","06","07","08","09","10","11","12","13", |
|||
"14","15","16","17","18","19","20","21","22","23","24","25","26","27", |
|||
"28","29","30","31"] |
|||
print( '\n' ) |
|||
def Decrypt(): |
|||
#decrypts an encoded message |
|||
global m,P,C,x,h,p,Text,y,w |
|||
P = [] |
|||
C = str(input("Enter ciphertext blocks:")) |
|||
C = C.lstrip('[') |
|||
C = C.rstrip(']') |
|||
C = C.split(',') |
|||
for i in range(len(C)): |
|||
x = decrypt(int(C[i]),d) |
|||
P.append(str(x)) |
|||
correct() |
|||
#print(P) |
|||
h = len(P[0]) |
|||
p = [] |
|||
for i in range(len(C)): |
|||
for n in range(int(h/2)): |
|||
p.append(str(P[i][(2*n):((2*n)+2)])) |
|||
Text = [] |
|||
for i in range(len(p)): |
|||
for j in range(len(letter)): |
|||
if str(p[i]) == number[j]: |
|||
Text.append(letter[j]) |
|||
PText = str() |
|||
for i in range(len(Text)): |
|||
PText = PText + str(Text[i]) |
|||
print("Plaintext is:", PText) |
|||
def Encrypt(): |
|||
#encrypts a plaintext message using the current key |
|||
global plaintext,numP,q,j,z,X,C |
|||
plaintext =(input("Enter Plaintext :")) |
|||
plaintext = plaintext.lower() |
|||
numP = [] |
|||
for i in range(len(plaintext)): |
|||
for j in range(len(letter)): |
|||
if plaintext[i] == letter[j]: |
|||
numP.append(number[j]) |
|||
h = (len(str(n))//2)-1 |
|||
q = len(numP)%h |
|||
for i in range(h-q): |
|||
numP.append(number[random.randint(0,25)]) |
|||
j = len(numP) / h |
|||
#print(numP) |
|||
X = [] |
|||
z = 0 |
|||
for m in range(h-1): |
|||
z+=2 |
|||
group(j,h,z) |
|||
k = len(X) |
|||
C = [] |
|||
for i in range(k): |
|||
b = X[i] |
|||
r = cipher(b,e) |
|||
C.append(r) |
|||
print("Ciphertext:",C) |
|||
print("Number of Ciphertext blocks:",len(C)) |
|||
def setup(): |
|||
global n,e,d |
|||
while True: |
|||
try: |
|||
n = int(input(" Enter a value for n :")) |
|||
if n > 2: |
|||
break |
|||
except ValueError: |
|||
print('please enter a number') |
|||
while 1!=2 : |
|||
try: |
|||
e = int(input(" Enter a value for e :")) |
|||
if e >= 2: |
|||
break |
|||
except ValueError: |
|||
print('please enter a number') |
|||
while True: |
|||
try: |
|||
d = int(input(" Enter a value for d. If d unknown, enter 0 :")) |
|||
if d >= 0: |
|||
break |
|||
except ValueError: |
|||
print('please enter a number') |
|||
#setup() |
|||
n = 2537 |
|||
e = 13 |
|||
d = 937 |
|||
print("To redefine n,e, or d, type 'n','e',... etc.") |
|||
print("To encrypt a message with the current key, type 'Encrypt'") |
|||
print("To decrypt a message with the current key, type 'Decrypt'") |
|||
print("Type quit to exit") |
|||
print( '\n' ) |
|||
print( '\n' ) |
|||
mm = str() |
|||
while mm != 'quit': |
|||
mm = input("Enter Command...") |
|||
if mm.lower() == 'encrypt': |
|||
Encrypt() |
|||
elif mm.lower() == 'decrypt': |
|||
Decrypt() |
|||
elif mm.lower() == 'n': |
|||
try: |
|||
print('current n = ',n) |
|||
n = int(input(" Enter a value for n :")) |
|||
except ValueError: |
|||
print('That is not a valid entry') |
|||
elif mm.lower() == 'help': |
|||
print("To redefine n,e, or d, type 'n','e',... etc.") |
|||
print("To encrypt a message with the current key, type 'Encrypt'") |
|||
print("To decrypt a message with the current key, type 'Decrypt'") |
|||
print("Type quit to exit") |
|||
print( '\n' ) |
|||
print( '\n' ) |
|||
elif mm.lower() == 'e': |
|||
try: |
|||
print('current e = ',e) |
|||
e = int(input(" Enter a value for e :")) |
|||
except ValueError: |
|||
print('That is not a valid entry') |
|||
elif mm.lower() == 'd': |
|||
try: |
|||
print('current d = ',d) |
|||
d = int(input(" Enter a value for d :")) |
|||
except ValueError: |
|||
print('That is not a valid entry') |
|||
else: |
|||
if mm != 'quit': |
|||
ii= random.randint(0,6) |
|||
statements = ["I sorry, Dave. I'm afraid i can't do that","I'm begging you....read the directions","Nah ahh ahh, didnt say the magic word","This input is....UNACCEPTABLE!!","Seriously....was that even a word???","Please follow the directions","Just type 'help' if you are really that lost"] |
|||
print(statements[ii])</lang> |
|||
Example use : |
|||
Any entered commands are '''not''' case sensitive, nor is the plaintext input. Commands must be spelled correctly. Ciphertext blocks are input all at once, but must be separated by commas. When decrypted, there may be random letters attached to the end of the message. The program does this in order to fill blocks completely, and not have orphaned characters. |
|||
<lang python>>>> |
|||
To redefine n,e, or d, type 'n','e',... etc. |
|||
To encrypt a message with the current key, type 'Encrypt' |
|||
To decrypt a message with the current key, type 'Decrypt' |
|||
Type quit to exit |
|||
Enter Command...ENCRYPT |
|||
Enter Plaintext :drink MORE Ovaltine |
|||
Ciphertext: [140, 2222, 1864, 1616, 821, 384, 2038, 2116, 2222, 205, 384, 2116, 45, 1, 2497, 793, 1864, 1616, 205, 41] |
|||
Number of Ciphertext blocks: 20 |
|||
Enter Command...decrypt |
|||
Enter ciphertext blocks:[140, 2222, 1864, 1616, 821, 384, 2038, 2116, 2222, 205, 384, 2116, 45, 1, 2497, 793, 1864, 1616, 205, 41] |
|||
Plaintext is: drink more ovaltineu |
|||
Enter Command...quit |
|||
>>> </lang> |
|||
=={{header|Racket}}== |
=={{header|Racket}}== |