Skip to content

Instantly share code, notes, and snippets.

@danilw
Last active November 30, 2024 01:49
Show Gist options
  • Save danilw/5c6cc2dc9e995e0c284b9c5511efe655 to your computer and use it in GitHub Desktop.
Save danilw/5c6cc2dc9e995e0c284b9c5511efe655 to your computer and use it in GitHub Desktop.
text_edit.py Python text editor with pass encryption with UTF-8 text support
#!/bin/python3
# text_edit.py
# Python text editor (from random Tinker based code) with pass encryption, with UTF-8 text support(non ASCII)
# usage:
# pip3 install pycryptodome
# python3 text_edit.py
# P.S. password strength:
# for 12-length password with upper-case symbol and number and special symbol:
# on single GPU that can process 2000x2000 - compute-passwords per frame at 60 fps
# there 333061772956016240000000 password compinations (assuming one upper-case and digit and special symbol is required)
# https://www.omnicalculator.com/statistics/password-combination
# it will require for that single GPU 44-million years (44005498)
# to find 12-length password in 44-years - 1000000(million) GPUs with that performance
import tkinter as tk
from tkinter import ttk
from tkinter import filedialog
from tkinter import messagebox
from tkinter import simpledialog
from tkinter import scrolledtext
import Crypto.Random, Crypto.Protocol.KDF, Crypto.Cipher.AES
tittle= "Text edit"
def cipherAES_GCM(pwd, nonce):
key = Crypto.Protocol.KDF.PBKDF2(pwd, nonce, count=100000)
return Crypto.Cipher.AES.new(key, Crypto.Cipher.AES.MODE_GCM, nonce=nonce, mac_len=16)
def new_file(e=None):
if not text_area.edit_modified():
text_area.delete('1.0', tk.END)
else:
save_file_as()
text_area.delete('1.0', tk.END)
text_area.edit_modified(0)
main_window.title(tittle)
def open_file(root=None):
global pwd
if not text_area.edit_modified():
try:
path = filedialog.askopenfile(filetypes = (("Text files", "*.txt"), ("All files", "*.*"))).name
main_window.title(tittle+' - ' + path)
with open(path, 'rb') as f:
content = f.read()
nonce, ciphertext, tag = content[:16], content[16:len(content)-16], content[-16:]
while True:
try:
if(root):
root.update_idletasks()
pwd = tk.simpledialog.askstring('Load', 'Password:', show="*").encode()
s = cipherAES_GCM(pwd, nonce).decrypt_and_verify(ciphertext, tag).decode()
text_area.delete('1.0', tk.END)
text_area.insert('1.0', s)
text_area.edit_modified(0)
break
except AttributeError:
exit()
except ValueError:
pass
except:
pass
else:
save_file_as()
text_area.edit_modified(0)
open_file()
def save(filex):
global pwd
if 'pwd' not in globals():
pwd = tk.simpledialog.askstring('Pass', 'Password:', show="*").encode()
nonce = Crypto.Random.new().read(16)
ciphertext = nonce + b''.join(cipherAES_GCM(pwd, nonce).encrypt_and_digest(text_area.get("1.0", tk.END).encode()))
with open(filex, 'wb') as f:
f.write(ciphertext)
text_area.edit_modified(False)
def save_file(e=None):
try:
path = main_window.title().split('-')[1][1:]
except:
path = ''
if path != '':
save(path)
else:
save_file_as()
text_area.edit_modified(0)
def save_file_as():
try:
path = filedialog.asksaveasfile(filetypes = (("Text files", "*.txt"), ("All files", "*.*"))).name
main_window.title(tittle+' - ' + path)
except:
return
save(path)
def close(e=None):
if not text_area.edit_modified() or tk.messagebox.askokcancel('Exit', "Some modifications have not been saved, do you really want to quit?", default=tk.messagebox.CANCEL):
main_window.destroy()
def find(e=False, findnext=False):
global query
if not findnext or 'query' not in globals():
query = tk.simpledialog.askstring('Find', 'Query:')
start = "1.0"
else:
start = text_area.index(tk.INSERT) + "+1c"
pos=''
if(query):
if(len(query)>0):
pos = text_area.search(query, start, stopindex="end", nocase=True, regexp=True)
if pos != '':
text_area.mark_set("insert", pos)
text_area.see("insert")
text_area.focus()
def select_all(event):
text_area.tag_add(tk.SEL, "1.0", tk.END)
text_area.mark_set(tk.INSERT, "1.0")
text_area.see(tk.INSERT)
return 'break'
main_window = tk.Tk()
main_window.bind('<Control-s>', save_file)
main_window.bind('<Control-f>', find)
main_window.bind('<F3>', lambda e: find(e, True))
main_window.title('Text edit')
main_window.geometry('1280x720')
main_window.protocol("WM_DELETE_WINDOW", close)
menubar = tk.Menu(main_window)
file_menu = tk.Menu(menubar, tearoff=0)
file_menu.add_command(label="New", command=new_file)
file_menu.add_command(label="Open", command=open_file)
file_menu.add_command(label="Save", command=save_file)
file_menu.add_command(label="Save as...", command=save_file_as)
file_menu.add_separator()
file_menu.add_command(label="Exit", command=close)
menubar.add_cascade(label="File", menu=file_menu)
text_area = tk.Text(main_window, wrap='none', bg='#272822', fg="#f8f8f2", insertbackground='#f8f8f2', font=("Consolas", 18))
text_area.pack(expand = tk.YES, fill = tk.BOTH, side = tk.LEFT)
main_window.bind('<Control-a>', select_all)
scroll_bar = ttk.Scrollbar(main_window, orient=tk.VERTICAL, command=text_area.yview)
scroll_bar.pack(fill=tk.Y, side=tk.RIGHT)
text_area['yscrollcommand'] = scroll_bar.set
s = "Welcome! This is a new file. Basic:\n* Save with CTRL+S\n* Open CTRL+O \n* Find a pattern with CTRL+F or F3"
text_area.insert(tk.END, s)
text_area.mark_set("insert", "1.0")
text_area.edit_modified(False)
text_area.focus()
main_window.config(menu=menubar)
tk.mainloop()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment