File Encryption / Decryption using RSA

    

Project Description

The RSA Encryptor Decryptor is like a digital lock and key system, created as part of an academic project. Think of it as a virtual toolbox built with Python, and it even has a friendly interface made with Tkinter.

Now, let's talk about what this virtual toolbox can do:

  1.  File Security: Imagine you have important digital files, and you want to protect them from prying eyes. This toolbox helps you lock and unlock these files. You tell it where your file is stored and give it a secret code (let's call it a key). The toolbox then performs some smart tricks (using XOR operations) to scramble your file, making it unreadable without the correct key. This way, only those who know the key can unscramble and access your files.

    For example, you might have a vacation photo album. You use this toolbox to lock it with a key. Now, even if someone gets hold of your album, they can't open it without the right key.
  2. Key Protection with RSA: In addition to file security, this toolbox has another cool feature. It helps you keep your keys safe. Keys are like the passwords that protect your digital stuff. With the RSA algorithm, it adds an extra layer of protection to your keys. So, you not only lock your files with a key but also keep that key super safe with RSA.
    It's like having a special, extra-secure vault for your secret codes (keys). Even if someone tries to sneak a peek, they can't understand the key without the right tools.

In simple terms, this project is your digital guardian. It helps you hide your important files and keeps your secret keys extra safe. It's like having a digital superhero that protects your digital stuff from the bad guys (or nosy friends).

Why I chose this Project?

I chose to work on the RSA Encryptor Decryptor project for a couple of reasons. Firstly, it was assigned as part of an academic project, and I saw it as an opportunity to dive into the world of cryptography, particularly the RSA algorithm. Exploring encryption techniques and understanding how digital locks and keys work aligns with the academic goals of gaining practical insights into secure data transmission.

Secondly, the project intrigued me because of its real-world applications. In today's digital age, safeguarding sensitive information is crucial, and the RSA algorithm is widely used for secure communication. By working on this project, I aimed to not only enhance my coding skills but also contribute to creating a tool that adds a layer of security to digital files and keys. It's a project that combines academic learning with practical applications, making it a valuable and engaging choice for my development journey.


Key Features:

  • File encryption and decryption using XOR operations
  • Graphical User Interface (GUI) built with Tkinter
  • Implementation of the RSA algorithm for key protection
  • Secure key management
  • Academic project for practical understanding of cryptography
  • Real-world application in data security
  • Python-based development

Tech Stack Used:

  • Python
  • Tkinter

Code Snippets:

1. Initialization and GUI Setup

import tkinter as tk
from PIL import Image, ImageTk
import os
root=tk.Tk()
root.tk.call('encoding','system','utf-8')
root.configure(background='white')
root.title('  My First Project in Python')
root.iconbitmap('logo.ico')
root.geometry("910x700")
This section initializes the Tkinter window, sets its background, title, and dimensions. It also imports necessary libraries for handling images and interacting with the operating system.

2. GUI Elements and Variables

name_var = tk.StringVar()
key_var = tk.IntVar()
encrypt_btn = tk.StringVar()
decrypt_btn = tk.StringVar()
message_var = tk.StringVar()
choose_var = tk.IntVar()
encryption_btn = tk.StringVar()
decryption_btn = tk.StringVar()
Here, variables are created to store values from user inputs, and StringVar is used to dynamically update labels in the GUI.

3. Logo Display

logo=Image.open('front.png').resize((500,250))
logo=ImageTk.PhotoImage(logo)
logo_label=tk.Label(image=logo,borderwidth=0)
logo_label.image=logo
logo_label.grid(row=0,column=0,columnspan=2,pady=1)
This part loads and displays the logo image in the GUI.

4. User Instructions

instructions = tk.Label(root, text="Select a File on your computer to Encrypt/Decrypt", font="Raleway", background="#eee", width=100)
instructions.grid(row=1, column=0, columnspan=2, pady=20)
It provides a user instruction label for clarity on the purpose of the application.

5. File Path and Encryption Key Entry

name_label = tk.Label(root, text='Enter File Path --', width=20, background="white").grid(row=2, column=0, pady=10)
name_entry = tk.Entry(root, textvariable=name_var, width=80, background="#eee").grid(row=2, column=1, pady=10)

key_label = tk.Label(root, text='Enter the Key --', width=20, background="white").grid(row=3, column=0, pady=10)
key_entry = tk.Entry(root, textvariable=key_var, width=80, background="#eee").grid(row=3, column=1, pady=10)
This part creates entry fields for the user to input the file path and encryption key.

6. File Encryption and Decryption Functions

def encrypt():
    # try block to handle exception
    try:
    	path = name_var.get()
    	# taking encryption key as input
    	key = key_var.get()
    	
    	# print path of file and encryption key that
    	# we are using
    	print('The path of file : ', path)
    	print('Key for encryption : ', key)
    	
    	# open file for reading purpose
    	fin = open(path, 'rb')
    	
    	# storing file data in variable "file"
    	file = fin.read()
    	fin.close()
    	
    	# converting file into byte array to
    	# perform encryption easily on numeric data
    	file = bytearray(file)
    
    	# performing XOR operation on each value of bytearray
    	for index, values in enumerate(file):
    		file[index] = values ^ key
    
    	# opening file for writing purpose
    	fin = open(path, 'wb')
    	
    	# writing encrypted data in file
    	fin.write(file)
    	fin.close()
    	encrypt_btn.set("Encrypted")
    
    	
    except Exception:
    	print('Error caught : ', Exception.__name__)
        
def decrypt():
    # try block to handle the exception
    try:
    	# take path of file as a input
    	path = name_var.get()
    	
    	# taking decryption key as input
    	key = key_var.get()
    	
    	# print path of file and decryption key that we are using
    	print('The path of file : ', path)
    	print('Note : Encryption key and Decryption key must be same.')
    	print('Key for Decryption : ', key)
    	
    	# open file for reading purpose
    	fin = open(path, 'rb')
    	
    	# storing file data in variable "file"
    	file = fin.read()
    	fin.close()
    	
    	# converting file into byte array to perform decryption easily on numeric data
    	file = bytearray(file)
    
    	# performing XOR operation on each value of bytearray
    	for index, values in enumerate(file):
    		file[index] = values ^ key
    
    	# opening file for writing purpose
    	fin = open(path, 'wb')
    	
    	# writing decryption data in file
    	fin.write(file)
    	fin.close()
    	decrypt_btn.set("Decrypted")
    
    
    except Exception:
    	print('Error caught : ', Exception.__name__)

These functions handle the encryption and decryption processes when the corresponding buttons are clicked.

7. RSA Algorithm Implementation

#RSA ALGORITHM STARTING
# STEP 1: Generate Two Large Prime Numbers (p,q) randomly
from random import randrange, getrandbits

def power(a,d,n):
  ans=1;
  while d!=0:
    if d%2==1:
      ans=((ans%n)*(a%n))%n
    a=((a%n)*(a%n))%n
    d>>=1
  return ans;

def MillerRabin(N,d):
  a = randrange(2, N - 1)
  x=power(a,d,N);
  if x==1 or x==N-1:
    return True;
  else:
    while(d!=N-1):
      x=((x%N)*(x%N))%N;
      if x==1:
        return False;
      if x==N-1:
        return True;
      d<<=1;
  return False;

def is_prime(N,K):
  if N==3 or N==2:
    return True;
  if N<=1 or N%2==0:
    return False;
  
  #Find d such that d*(2^r)=X-1
  d=N-1
  while d%2!=0:
    d/=2;

  for _ in range(K):
    if not MillerRabin(N,d):
      return False;
  return True;  
  
def generate_prime_candidate(length):
  # generate random bits
  p = getrandbits(length)
  # apply a mask to set MSB and LSB to 1
  # Set MSB to 1 to make sure we have a Number of 1024 bits.
  # Set LSB to 1 to make sure we get a Odd Number.
  p |= (1 << length - 1) | 1
  return p

def generatePrimeNumber(length):
  A=4
  while not is_prime(A, 128):
        A = generate_prime_candidate(length)
  return A

length=5
P=generatePrimeNumber(length)
Q=generatePrimeNumber(length)

#Step 2: Calculate N=P*Q
N=P*Q

#Step 3: Calculate Euler Totient Function = (P-1)*(Q-1)
eulerTotient=(P-1)*(Q-1)

#Step 4: Find E such that GCD(E,eulerTotient)=1(i.e., e should be co-prime) such that it satisfies this condition:-  1<E<eulerTotient

def GCD(a,b):
  if a==0:
    return b;
  return GCD(b%a,a)

E=generatePrimeNumber(4)
while GCD(E,eulerTotient)!=1:
  E=generatePrimeNumber(4)

# Step 5: Find D. 
#For Finding D: It must satisfies this property:-  (D*E)Mod(eulerTotient)=1;
#Now we have two Choices
# 1. That we randomly choose D and check which condition is satisfying above condition.
# 2. For Finding D we can Use Extended Euclidean Algorithm: ax+by=1 i.e., eulerTotient(x)+E(y)=GCD(eulerTotient,e)
#Here, Best approach is to go for option 2.( Extended Euclidean Algorithm.)

def gcdExtended(E,eulerTotient):
  a1,a2,b1,b2,d1,d2=1,0,0,1,eulerTotient,E
  while d2!=1:
    # k
    k=(d1//d2)
    #a
    temp=a2
    a2=a1-(a2*k)
    a1=temp

    #b
    temp=b2
    b2=b1-(b2*k)
    b1=temp

    #d
    temp=d2
    d2=d1-(d2*k)
    d1=temp

    D=b2

  if D>eulerTotient:
    D=D%eulerTotient
  elif D<0:
    D=D+eulerTotient
  return D

D=gcdExtended(E,eulerTotient)
public = (E,N)
private = (D,N)

def encryption(pub_key,n_text):
    e,n=pub_key
    x=''
    m=0
    for i in n_text:
        m=ord(i)
        c=(m**e)%n
        x+=chr(c)
    return x

'''DECRYPTION ALGORITHM'''
def decryption(priv_key,c_text):
    d,n=priv_key
    x=''
    m=0
    for i in c_text:
        m=ord(i)
        c=(m**d)%n
        x+=chr(c)
    return x
This section contains functions for RSA key generation, encryption, and decryption.

8. Message Entry and Choose Option

#def submit message and choose option
message_label = tk.Label(root,text='Type your content to encrypt or decrypt:',width=100,background="white").grid(row=6,column=0,columnspan=2,pady=10)
message_entry=tk.Entry(root,textvariable=message_var,width=100,background="#eee").grid(row=7,column=0,columnspan=2,pady=10)
   
choose_label = tk.Label(root,text="Type '1' for encryption and '2' for decrytion:",width=50,background="white").grid(row=8,column=0,columnspan=2,pady=10)
choose_entry=tk.Entry(root,textvariable=choose_var,width=50,background="#eee").grid(row=8,column=1,columnspan=2,pady=10)

def addToClipBoard(text):
    command = 'echo ' + text + '| clip'
    os.system(command)
It provides entry fields for the user to input the message and choose between encryption and decryption.

9. Submit Function

def submit():
    #Message1
    message = message_var.get()
    #Choose Encrypt or Decrypt and Print
    choose = choose_var.get()
    if(choose==1):
        msg=tk.Label(root,bg='white')
        msg.config(text="Your encrypted message is : ")
        msg.grid(row=9,column=1)
        value=tk.Label(root)
        value.config(text=encryption(public,message))
        value.grid(row=10,column=1,padx=10,pady=10)
        encryption_btn.set("Data Encypted")
        refresh_btn=tk.Button(root,background='#2fbf71',fg='white',text="Refresh",command=lambda:refresh())
        refresh_btn.grid(row=11,column=1)
        copy_btn=tk.Button(root,background='#2fbf71',fg='white',text="Copy",command=lambda:addToClipBoard(encryption(public,message)))
        copy_btn.grid(row=11,column=2)
        def refresh():
            msg.grid_forget()
            value.grid_forget()
        print("Your encrypted message is:",encryption(public,message))
        print("Thank you for using the RSA Encryption")
    elif(choose==2):
        msg=tk.Label(root,bg='white')
        msg.config(text="Your Decrypted message is : ")
        msg.grid(row=9,column=1)
        value=tk.Label(root)
        value.config(text=decryption(private,message))
        value.grid(row=10,column=1,padx=10,pady=10)
        encryption_btn.set("Data Decrypted")
        refresh_btn=tk.Button(root,background='#2fbf71',fg='white',text="Refresh",command=lambda:refresh())
        refresh_btn.grid(row=11,column=1)
        def refresh():
            msg.grid_forget()
            value.grid_forget()
        print("Your decrypted message is:",decryption(private,message))
        print("Thank you for using the RSA Encryption")
    else:
        msg=tk.Label(root,text="        Wrong Decision!!!          ",fg='red',bg='white').grid(row=9,column=1)
        value=tk.Label(root,text=encryption(public,message),fg='white',bg='white').grid(row=10,column=1,padx=10,pady=10)

    
This function is triggered when the user clicks the "Encrypt/Decrypt data" button, handling message submission and encryption/decryption based on user input.

10. Open File and Decrypt Buttons

# open file button
open_button = tk.Button(root, width=50,background="cyan", textvariable=encrypt_btn, command=lambda:encrypt())
encrypt_btn.set("Encrypt a file")
open_button.grid(row=4,column=0)
decrypt_button = tk.Button(root, width=50,background="cyan",textvariable=decrypt_btn, command=lambda:decrypt())
decrypt_btn.set("Decrypt a file")
decrypt_button.grid(row=4,column=1)

instruction=tk.Label(root, text="Write Your Data to Encrypt/Decrypt", font="Raleway",background="#eee",width=100)
instruction.grid(row=5,column=0,columnspan=2,pady=20)

encryption_button = tk.Button(root, width=50,background="cyan", textvariable=encryption_btn, command=submit)
encryption_btn.set("Encrypt/Decrypt data")
encryption_button.grid(row=9,column=0)
These buttons trigger the file encryption and decryption functions.

11. Execution of GUI

root.mainloop()
This line runs the Tkinter event loop, allowing the GUI to be interactive.

Understanding each of these sections helps in understanding how the RSA encryption/decryption application is structured and functions.

Challenges Faced:

A significant challenge encountered during this project was related to the implementation of the graphical user interface (GUI). The challenge encompassed understanding the intricacies of Tkinter, the library used for GUI development in Python. Challenges included arranging elements, ensuring seamless user interactions, and creating an intuitive layout for users, especially considering the sensitive nature of encryption and decryption tasks.

Navigating through these challenges was a valuable learning experience. It required persistent research, exploration, and practical application to overcome the hurdles associated with GUI development. Ultimately, addressing this challenge contributed significantly to my growth as a developer, enhancing both technical and design-oriented skills in the realm of graphical user interfaces.

User Interface (UI)

Here are Some of the Snaps to have a quick look:



For Wrong Type Selection:

Public Code Repository:

You can find the source code for this project on GitHub.

References

For those interested in exploring the technologies and concepts discussed in this article, the following resources are recommended: