diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..7f3b5d5 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,8 @@ +FROM python:3.12-slim + +WORKDIR /opt/McEliece +COPY . . + +RUN pip install --no-cache-dir -r requirements.txt + +CMD [ "python", "McEliece_console.py" ] diff --git a/app_local/McEliece_console_v2.py b/McEliece_console.py similarity index 100% rename from app_local/McEliece_console_v2.py rename to McEliece_console.py diff --git a/app_local/readme.txt b/README.md similarity index 100% rename from app_local/readme.txt rename to README.md diff --git a/app_local/McEliece.pdf b/app_local/McEliece.pdf deleted file mode 100644 index 38fc32d..0000000 Binary files a/app_local/McEliece.pdf and /dev/null differ diff --git a/app_local/McEliece_GUI.py b/app_local/McEliece_GUI.py deleted file mode 100644 index 01b8d79..0000000 --- a/app_local/McEliece_GUI.py +++ /dev/null @@ -1,130 +0,0 @@ -#pyinstaller -F -w -i "icon.ico" McEliece_GUI.py - -import cryptosystem_core as core -import tkinter as tk - -def mymessagebox(fontsize, butsize, mytitle, mytext): - toplevel = tk.Toplevel(window) - toplevel.title(mytitle) - toplevel.geometry(f"600x400+{window.winfo_x()+40}+{window.winfo_y()+15}") - toplevel.resizable(False, False) - l = tk.Label(toplevel, text = mytext, font = ("TkDefaultFont", fontsize)) - l.pack() - b = tk.Button(toplevel, text = "Close", command = toplevel.destroy, width = 10, font = ("TkDefaultFont", butsize)) - b.pack() - -def show_error(): - mymessagebox(30, 30, "Error!", "ERROR!\n\nPress help button\nto show common\nmistakes in usage.\n") - -def button0_click(): - mymessagebox(15, 15, "Source code: github.com/vovuas2003/McEliece", "Program can work slow and doesn't response, it is normal.\n1st line = current configuration of cryptosystem.\n2nd line = public key (send to anybody).\n3rd line = first half (s) of private key (keep in secret!).\n4th line = second half (p) of private key (keep in secret!).\nBig field = place for writing text or pasting message.\nGenerate keys = rewrite all 3 keys.\nEncrypt = pubkey is required.\nDecrypt = both privkeys are required.\nYou can restore any key from the other two.\nConfig = change cryptosystem parameters n and k.\n(two numbers separated by a space, default: 255 210)\n(255 mod n = 0; 255 = 3 * 5 * 17)\n(2 <= k <= n; (n - k) div 2 bytes are randomly changed)\nPT! = just easter egg :)") - -def button1_click(): - try: - new_text1, new_text2, new_text3 = core.generate() - entry1.delete(0, tk.END) - entry1.insert(0, new_text1) - entry2.delete(0, tk.END) - entry2.insert(0, new_text2) - entry3.delete(0, tk.END) - entry3.insert(0, new_text3) - except: - show_error() - -def button2_click(): - try: - G = entry1.get() - text = entry4.get("1.0", "end-1c") - new_text4 = core.encrypt(G, text) - entry4.delete("1.0", tk.END) - entry4.insert("1.0", new_text4) - except: - show_error() - -def button3_click(): - try: - S = entry2.get() - P = entry3.get() - msg = entry4.get("1.0", "end-1c") - new_text4 = core.decrypt(S, P, msg) - entry4.delete("1.0", tk.END) - entry4.insert("1.0", new_text4) - except: - show_error() - -def button4_click(): - try: - S = entry2.get() - P = entry3.get() - new_text1 = core.restore_G(S, P) - entry1.delete(0, tk.END) - entry1.insert(0, new_text1) - except: - show_error() - -def button5_click(): - try: - G = entry1.get() - P = entry3.get() - new_text2 = core.break_S(G, P) - entry2.delete(0, tk.END) - entry2.insert(0, new_text2) - except: - show_error() - -def button6_click(): - try: - G = entry1.get() - S = entry2.get() - new_text3 = core.break_P(G, S) - entry3.delete(0, tk.END) - entry3.insert(0, new_text3) - except: - show_error() - -def button7_click(): - try: - core.config(entry0.get()) - except: - entry0.delete(0, tk.END) - entry0.insert(0, str(core.n) + " " + str(core.k)) - show_error() - -def button8_click(): - mymessagebox(200, 15, "PT!" * 25, "PT!") - -window = tk.Tk() -window.title("McEliece by vovuas2003") - -frame_buttons = tk.Frame(window) -frame_buttons.pack(side = tk.TOP, fill = tk.X) - -buttons = [] -but_names = ["help", "generate keys", "encrypt text", "decrypt message", "pubkey = s + p", "s = pubkey + p", "p = pubkey + s", "change config", "PT!"] -but_com = [button0_click, button1_click, button2_click, button3_click, button4_click, button5_click, button6_click, button7_click, button8_click] -for i in range(9): - buttons.append(tk.Button(frame_buttons, text = but_names[i], command = but_com[i])) - -for button in buttons: - button.pack(side = tk.LEFT) - -entry0 = tk.Entry(window, width = 50) -entry1 = tk.Entry(window, width = 50) -entry2 = tk.Entry(window, width = 50) -entry3 = tk.Entry(window, width = 50) -entry4 = tk.Text(window, height = 20, width = 50) - -entry0.insert(0, "255 210 (default config)") -entry1.insert(0, "pubkey") -entry2.insert(0, "privkey s") -entry3.insert(0, "privkey p") -entry4.insert("1.0", "Write a text or paste a message here!\nAll utf-8 symbols are supported, e.g. alt codes and Russian text.\n\n(use ctrl+a before crtl+v or ctrl+c)\n(switch keyboard layout to english to use these shortcuts)\n\nYou can't resize window, but can scroll down.\nProgram can work slow, don't kill it please :)") - -entry0.pack() -entry1.pack() -entry2.pack() -entry3.pack() -entry4.pack(fill = tk.BOTH, expand = True) - -window.resizable(False, False) -window.mainloop() diff --git a/app_local/McEliece_console.py b/app_local/McEliece_console.py deleted file mode 100644 index cdc302a..0000000 --- a/app_local/McEliece_console.py +++ /dev/null @@ -1,445 +0,0 @@ -#pyinstaller -F -i "icon.ico" McEliece_console.py - -import hashlib -import getpass -import random -import base64 - -def main(): - safe_start() - -def safe_start(): - try: - start_menu() - except: - print("\nUnknown error (maybe ctrl+c), emergency exit!") - -def start_menu(): - f = True - print("\nA soldering iron is into a black hole.") - #thermorectal cryptanalysis - if myhash(getpass.getpass("Login: ")) != 1314399736851798576: - f = False - if myhash(getpass.getpass("Password: ")) != 192441972608755898: - f = False - if f: - print("Authorization successful, wait a bit.") - menu() - else: - print("Permission denied.") - print("\nPress ENTER to exit.", end = '') - input() - -def menu(): - import cryptosystem_core as core - print("\nMcEliece cryptosystem implementation by vovuas2003.\n") - print("All necessary txt files must be in utf-8 and located in the directory with this exe program.\n") - info = "Menu numbers: 0 = exit; 1 = generate keys, 2 = encrypt, 3 = decrypt,\n4 = restore pubkey, 5 = break privkey_s, 6 = break privkey_p;\n-0 = init all txt files, -1 = init keys, -2 = init text, -3 = init message,\n-4 = init pubkey, -5 = init privkey_s, -6 = init privkey_p;\nc = config, b = binary menu, u = unsafe keygen by password, h = help.\n" - err = "Error! Check command info and try again!\n" - ok = "Operation successful.\n" - inp = [str(i) for i in range(7)] + ['-' + str(i) for i in range(7)] + ['c', 'b', 'h', 'u'] + ['1337', '-1337'] - print(info) - while True: - s = input("Menu number: ") - while s not in inp: - s = input("Wrong menu number, h = help: ") - if s == 'h': - print(info) - elif s == 'b': - print("Go to binary files encryption menu? Don't forget to generate keys and change config before that (if you want)!") - if(not get_yes_no()): - continue - try: - if(bin_menu(core)): - break - except: - raise Exception() - elif s == 'c': - print("Default config is 255 210, current is " + str(core.n) + " " + str(core.k) + ". Change config?") - if(not get_yes_no()): - continue - try: - print("Config is two numbers n >= k >= 2; (3 * 5 * 17) mod n = 0. Larger values = larger keys.\nRandomly change (n - k) div 2 bytes during encryption, but add (n - k + 1) bytes to each chunk with len (k - 1).") - core.config(input("Write n and k separated by a space: ")) - print(ok) - except: - print(err) - elif s == '0': - print("\nGood luck!") - break - elif s == 'u': - print("WARNING: setting sha256hash(password) mod 2^32 as random seed is VERY unsafe practice!\nIt is better to use menu number 1 for independent random.") - print("This operation will rewrite pubkey.txt, privkey_s.txt and privkey_p.txt; are you sure?") - if(not get_yes_no()): - continue - try: - seed = normalhash(getpass.getpass("Any password for hashing: ")) - G, S, P = core.unsafe_generate(seed) - write_txt("pubkey", G) - write_txt("privkey_s", S) - write_txt("privkey_p", P) - print(ok) - except: - print(err) - elif s == '1': - print("This operation will rewrite pubkey.txt, privkey_s.txt and privkey_p.txt; are you sure?") - if(not get_yes_no()): - continue - try: - G, S, P = core.generate() - write_txt("pubkey", G) - write_txt("privkey_s", S) - write_txt("privkey_p", P) - print(ok) - except: - print(err) - elif s == '2': - print("Write your text into text.txt; pubkey.txt is required, message.txt will be rewritten.") - if(not get_yes_no()): - continue - try: - G = read_txt("pubkey") - text = read_txt("text") - msg = core.encrypt(G, text) - write_txt("message", msg) - print(ok) - except: - print(err) - elif s == '3': - print("You need message.txt, privkey_s.txt and privkey_p.txt; text.txt will be rewritten.") - if(not get_yes_no()): - continue - try: - S = read_txt("privkey_s") - P = read_txt("privkey_p") - msg = read_txt("message") - text = core.decrypt(S, P, msg) - write_txt("text", text) - print(ok) - except: - print(err) - elif s == '4': - print("You need privkey_s.txt and privkey_p.txt; pubkey.txt will be rewritten.") - if(not get_yes_no()): - continue - try: - S = read_txt("privkey_s") - P = read_txt("privkey_p") - G = core.restore_G(S, P) - write_txt("pubkey", G) - print(ok) - except: - print(err) - elif s == '5': - print("You need pubkey.txt and privkey_p.txt; privkey_s.txt will be rewritten.") - if(not get_yes_no()): - continue - try: - G = read_txt("pubkey") - P = read_txt("privkey_p") - S = core.break_S(G, P) - write_txt("privkey_s", S) - print(ok) - except: - print(err) - elif s == '6': - print("You need pubkey.txt and privkey_s.txt; privkey_p.txt will be rewritten.") - if(not get_yes_no()): - continue - try: - G = read_txt("pubkey") - S = read_txt("privkey_s") - P = core.break_P(G, S) - write_txt("privkey_p", P) - print(ok) - except: - print(err) - elif s == '-0': - print("Create (or make empty) all 5 necessary txt files in right utf-8 encoding.") - if(not get_yes_no()): - continue - try: - write_txt("pubkey", "") - write_txt("privkey_s", "") - write_txt("privkey_p", "") - write_txt("text", "") - write_txt("message", "") - print(ok) - except: - print(err) - elif s == '-1': - print("Create (or make empty) all 3 keys txt files in right utf-8 encoding.") - if(not get_yes_no()): - continue - try: - write_txt("pubkey", "") - write_txt("privkey_s", "") - write_txt("privkey_p", "") - print(ok) - except: - print(err) - elif s == '-2': - print("Create (or make empty) text.txt in right utf-8 encoding.") - if(not get_yes_no()): - continue - try: - write_txt("text", "") - print(ok) - except: - print(err) - elif s == '-3': - print("Create (or make empty) message.txt in right utf-8 encoding.") - if(not get_yes_no()): - continue - try: - write_txt("message", "") - print(ok) - except: - print(err) - elif s == '-4': - print("Create (or make empty) pubkey.txt in right utf-8 encoding.") - if(not get_yes_no()): - continue - try: - write_txt("pubkey", "") - print(ok) - except: - print(err) - elif s == '-5': - print("Create (or make empty) privkey_s.txt in right utf-8 encoding.") - if(not get_yes_no()): - continue - try: - write_txt("privkey_s", "") - print(ok) - except: - print(err) - elif s == '-6': - print("Create (or make empty) privkey_p.txt in right utf-8 encoding.") - if(not get_yes_no()): - continue - try: - write_txt("privkey_p", "") - print(ok) - except: - print(err) - elif s == '1337': - c = input("Move the soldering iron into the black hole number: ") - try: - PT(int(c)) - except: - print("Iron: 'I don't know this hole.'") - continue - elif s == '-1337': - print("Do you want to format your system disk?") - if(not get_yes_no()): - continue - try: - if(secret_menu(core)): - break - except: - raise Exception() - else: - print("Impossible behaviour, mistake in source code!\nThe string allowed in the inp array is not bound to the call of any function!") - break - -def bin_menu(core): - print("\nFirst line in binary.txt is a name of the original file (with extension), you can edit it.") - print("Default config is 255 210, current is " + str(core.n) + " " + str(core.k) + ".") - info = "Binary menu numbers: 0 = go back to common menu; 1 = encrypt, 2 = decrypt;\n-0 = init binary.txt; -1 = to base64, -2 = from base64; h = help.\n" - err = "Error! Check command info and try again!\n" - ok = "Operation successful.\n" - inp = [str(i) for i in range(3)] + ['-' + str(i) for i in range(3)] + ['h'] - print(info) - while True: - s = input("Binary menu number: ") - while s not in inp: - s = input("Wrong menu number, h = help: ") - if s == 'h': - print(info) - elif s == '0': - print("Going back to common menu.\n") - break - elif s == '1': - print("You need pubkey.txt and any file that you want to encrypt; binary.txt will be rewritten.") - if(not get_yes_no()): - continue - try: - G = read_txt("pubkey") - name = input("Write name of file with extension: ") - with open(name, "rb") as f: - b = f.read() - out = core.bin_encrypt(G, b) - write_txt("binary", name + '\n' + out) - print(ok) - except: - print(err) - elif s == '2': - print("You need privkey_s.txt, privkey_p.txt and binary.txt; name of new file is the first string in binary.txt.") - if(not get_yes_no()): - continue - try: - S = read_txt("privkey_s") - P = read_txt("privkey_p") - name, msg = read_txt("binary").split('\n') - text = core.bin_decrypt(S, P, msg) - with open(name, "wb") as f: - f.write(text) - print(ok) - except: - print(err) - elif s == '-0': - print("Create (or make empty) binary.txt in right utf-8 encoding.") - if(not get_yes_no()): - continue - try: - write_txt("binary", "") - print(ok) - except: - print(err) - elif s == '-1': - print("Convert any file to base64 string without any encryption; binary.txt will be rewritten.") - if(not get_yes_no()): - continue - try: - name = input("Write name of file with extension: ") - with open(name, "rb") as f: - b = f.read() - out = base64.b64encode(b).decode() - write_txt("binary", name + '\n' + out) - print(ok) - except: - print(err) - elif s == '-2': - print("Convert binary.txt from base64; name of new file is the first string in binary.txt.") - if(not get_yes_no()): - continue - try: - name, msg = read_txt("binary").split('\n') - text = base64.b64decode(msg) - with open(name, "wb") as f: - f.write(text) - print(ok) - except: - print(err) - else: - print("Impossible behaviour, mistake in source code!\nThe string allowed in the inp array is not bound to the call of any function!") - return 1 - return 0 - -def secret_menu(core): - #1qaz@WSX - if myhash(getpass.getpass("canp: ")) == 1355332552418299328: - print("Authorization successful.") - else: - print("Permission denied.") - return 0 - print("\nHidden input from keyboard, writing to secret_message.txt.") - print("Default config is 255 210, current is " + str(core.n) + " " + str(core.k) + ".") - info = "Secret menu numbers: 0 = go back; 1 = encrypt, 2 = decrypt; -0 = init txt; h = help.\n" - err = "Error! Check command info and try again!\n" - ok = "Operation successful.\n" - inp = [str(i) for i in range(3)] + ['-0'] + ['h'] - print(info) - while True: - s = input("Secret menu number: ") - while s not in inp: - s = input("Wrong menu number, h = help: ") - if s == 'h': - print(info) - elif s == '0': - print("Going back to common menu.\n") - break - elif s == '1': - print("You need pubkey.txt; secret_message.txt will be rewritten.") - if(not get_yes_no()): - continue - try: - G = read_txt("pubkey") - text = getpass.getpass("Secret text: ") - msg = core.encrypt(G, text) - write_txt("secret_message", msg) - print(ok) - except: - print(err) - elif s == '2': - print("You need privkey_s.txt, privkey_p.txt and secret_message.txt.") - if(not get_yes_no()): - continue - try: - S = read_txt("privkey_s") - P = read_txt("privkey_p") - msg = read_txt("secret_message") - text = core.decrypt(S, P, msg) - print('\nSecret text: ' + text + '\n') - print(ok) - except: - print(err) - elif s == '-0': - print("Create (or make empty) secret_message.txt in right utf-8 encoding.") - if(not get_yes_no()): - continue - try: - write_txt("secret_message", "") - print(ok) - except: - print(err) - else: - print("Impossible behaviour, mistake in source code!\nThe string allowed in the inp array is not bound to the call of any function!") - return 1 - return 0 - -def get_yes_no(): - s = input("Confirm (0 = go back, 1 = continue): ") - while s not in ['0', '1']: - s = input("Try again, 0 or 1: ") - return int(s) - -def myhash(s, m = 2**61 - 1, p = 257): - a = 0 - for i in range(len(s)): - a = ((a * p) % m + ord(s[i])) % m - return a - -def normalhash(s): - return int(hashlib.sha256(bytearray(s, 'utf-8')).hexdigest(), 16) - -def PT(m, M = 3): - if m == 0: - print("Iron: 'OK, I will choose the number by myself.'") - while m == 0: - m = random.randint(-M, M) - s = "PT!" - p = " " - f = False - if m < 0: - s, p = p, s - m *= -1 - f = True - if m > M: - print("Iron: 'Are you sure to move me so far?'") - if(not get_yes_no()): - return - print() - if f: - print(p * (10 * m + 1)) - print(p + (s * 3 + p + s * 3 + p + s + p) * m) - print(p + (s + p + s + p * 2 + s + p * 2 + s + p) * m) - print(p + (s * 3 + p * 2 + s + p * 2 + s + p) * m) - print(p + (s + p * 4 + s + p * 4) * m) - print(p + (s + p * 4 + s + p * 2 + s + p) * m) - if f: - print(p * (10 * m + 1)) - print() - -def write_txt(name, string): - with open(name + ".txt", "w", encoding = "utf-8") as f: - f.write(string) - -def read_txt(name): - with open(name + ".txt", "r", encoding = "utf-8") as f: - out = f.read() - return out - -if __name__ == "__main__": - main() diff --git a/app_local/cryptosystem_core.py b/app_local/cryptosystem_core.py deleted file mode 100644 index 4d49b63..0000000 --- a/app_local/cryptosystem_core.py +++ /dev/null @@ -1,246 +0,0 @@ -#McEliece cryptosystem implementation by vovuas2003 - -#Usage: -#G = pubkey; S and P = privkeys; text = plaintext; msg = encrypted text -#all these variables are strings, so it's easy to integrate this code into any project (check GUI and console examples) -#text must be in utf-8 encoding (e.g. force encoding when open txt files, check console example) -#keys and messages are saved as base64 strings -#you can use bin_encrypt and bin_decrypt functions if text is a byte array (check console example) - -''' -import cryptosystem_core as core -G, S, P = core.generate() -G, S, P = core.unsafe_generate(seed) #e.g. seed = hash(password) -msg = core.encrypt(G, text) -text = core.decrypt(S, P, msg) -G = core.restore_G(S, P) -S = core.break_S(G, P) -P = core.break_P(G, S) -core.config("255 210") #this is the default configuration, NO NEED TO WRITE THIS LINE FOR INITIALIZATION, it is just an example of using the function -#these parameters n and k affect the length of the keys, messages and the number of erroneous bytes in the message -#larger values = larger keys; randomly change (n - k) div 2 bytes during encryption, but add (n - k + 1) bytes to each chunk with len (k - 1). -#see the comments below to understand the requirements for n and k (or check console example) -''' - -#if you want to figure out how the code below works, keep in mind that -#G_ is a pubkey, G is a Reed Solomon code matrix and P is saved as permutation array -#to use the core of the cryptosystem, you don't need to think about it, just write the code as in the example above - -import numpy as np -import galois -import random -import base64 - -order = 256 #p^m = 2**8; encrypt each byte and save in base64 format -n = 255 #(order - 1) mod n = 0 for Reed Solomon code; 255 = 3 * 5 * 17 = (order - 1) -k = 210 #2 <= k <= n; randomly change (n - k) div 2 bytes during encryption -GF = galois.GF(2, 8, irreducible_poly = "x^8 + x^4 + x^3 + x^2 + 1", primitive_element = "x", verify = False) #hardcoded galois.GF(2**8).properties for pyinstaller -rs = galois.ReedSolomon(n, k, field = GF) - -def main(): #for testing - pass - -def config(string): - global n - global k - global rs - try: - nn, kk = map(int, string.split()[:2]) - if kk < 2: - raise Exception() - rrss = galois.ReedSolomon(nn, kk, field = GF) - except: - raise Exception() - else: - n = nn - k = kk - rs = rrss - -def generate(): - S = generate_S() - G = rs.G - P, p = generate_P() - G_ = S @ G @ P - return write_pubkey(G_), write_privkey_s(S), write_privkey_p(p) - -def generate_S(): - S = GF.Random((k, k)) - while np.linalg.det(S) == 0: - S = GF.Random((k, k)) - return S - -def generate_P(): - r = [i for i in range(n)] - p = [] - for i in range(n): - p.append(r.pop(random.randint(0, n - 1 - i))) - P = GF.Zeros((n, n)) - for i in range(n): - P[i, p[i]] = 1 - return P, p - -def unsafe_generate(h): - seed = h % (2**32) - S = unsafe_generate_S(seed) - G = rs.G - P, p = unsafe_generate_P(seed) - G_ = S @ G @ P - return write_pubkey(G_), write_privkey_s(S), write_privkey_p(p) - -def unsafe_generate_S(seed): - pseudo = np.random.RandomState(seed) - S = GF(pseudo.randint(0, order, (k, k))) - while np.linalg.det(S) == 0: - S = GF(pseudo.randint(0, order, (k, k))) - return S - -def unsafe_generate_P(seed): - pseudo = np.random.RandomState(seed) - p = [i for i in range(n)] - pseudo.shuffle(p) - P = GF.Zeros((n, n)) - for i in range(n): - P[i, p[i]] = 1 - return P, p - -def write_pubkey(G_): - rows = [bytes(row) for row in G_] - row = bytes([i for j in rows for i in j]) - return base64.b64encode(row).decode() - -def write_privkey_s(S): - rows = [bytes(row) for row in S] - row = bytes([i for j in rows for i in j]) - return base64.b64encode(row).decode() - -def write_privkey_p(p): - return base64.b64encode(bytes(p)).decode() - -def read_pubkey(out): - out = [int(i) for i in base64.b64decode(out)] - out = [out[i - n : i] for i in range(n, n * k + n, n)] - return out - -def read_privkey_s(out): - out = [int(i) for i in base64.b64decode(out)] - out = [out[i - k : i] for i in range(k, k * k + k, k)] - return out - -def read_privkey_p(out): - return [int(i) for i in base64.b64decode(out)] - -def build_P(p): - P = GF.Zeros((n, n)) - for i in range(n): - P[i, p[i]] = 1 - return P - -def build_P_inv(p): - P = GF.Zeros((n, n)) - for i in range(n): - P[p[i], i] = 1 - return P - -def pad_message(msg: bytes, pad_size: int) -> list[int]: - padding = pad_size - (len(msg) % pad_size) - return list(msg + padding.to_bytes() * padding) - -def unpad_message(msg): - padding_byte = msg[-1] - for i in range(1, padding_byte + 1): - if msg[-i] != padding_byte: - #print("Wrong privkey!") - raise Exception() - return msg[: -padding_byte] - -def encrypt(key, text): - return bin_encrypt(key, text.encode("utf-8")) - -def decrypt(s, p, msg): - return bin_decrypt(s, p, msg).decode("utf-8") - -def bin_encrypt(key, text): - G_ = GF(read_pubkey(key)) - out = bytes() - while len(text) > k - 1: - tmp = text[: k - 1] - text = text[k - 1 :] - out += encrypt_one(G_, tmp) - out += encrypt_one(G_, text) - return base64.b64encode(out).decode() - -def bin_decrypt(s, p, msg): - S_inv = np.linalg.inv(GF(read_privkey_s(s))) - P_inv = GF(build_P_inv(read_privkey_p(p))) - msg = [int(i) for i in base64.b64decode(msg)] - msg = [msg[i - n : i] for i in range(n, len(msg) + n, n)] - msg = [decrypt_one(S_inv, P_inv, GF(i)) for i in msg] - msg = [i for j in msg for i in j] - msg = bytes(msg) - return msg - -def encrypt_one(G_, text): - msg = pad_message(text, k) - m = GF(msg) - c = m.T @ G_ - t = (n - k) // 2 - z = np.zeros(n, dtype = int) - p = [i for i in range(n)] - for i in range(t): - ind = p.pop(random.randint(0, n - 1 - i)) - z[ind] += random.randint(1, order - 1) - z[ind] %= order - c = c + GF(z) - return bytes(c) - -def decrypt_one(S_inv, P_inv, msg): - msg = msg @ P_inv - msg, e = rs.decode(msg, errors = True) - if e == -1: - #print("Too many erroneous values in message!") - raise Exception() - msg = msg @ S_inv - msg = [int(i) for i in msg] - msg = unpad_message(msg) - return msg - -def restore_G(s, p): - S = GF(read_privkey_s(s)) - G = rs.G - P = GF(build_P(read_privkey_p(p))) - G_ = S @ G @ P - return write_pubkey(G_) - -def break_S(key, p): - G_ = GF(read_pubkey(key)) - P_inv = GF(build_P_inv(read_privkey_p(p))) - S = G_ @ P_inv - S = S[:, : k] - return write_privkey_s(S) - -def break_P(key, s): - G_ = GF(read_pubkey(key)) - S_inv = np.linalg.inv(GF(read_privkey_s(s))) - G = rs.G - G = G.T - G = [[int(i) for i in j] for j in G] - GP = S_inv @ G_ - GP = GP.T - GP = [[int(i) for i in j] for j in GP] - p = [0 for i in range(n)] - f = False - for i in range(n): - f = False - for j in range(n): - if G[i] == GP[j]: - p[i] = j - f = True - break - if f: - continue - #print("Wrong pubkey and privkey_s combination!") - raise Exception() - return write_privkey_p(p) - -if __name__ == "__main__": - main() diff --git a/app_local/icon.ico b/app_local/icon.ico deleted file mode 100644 index c7a31c2..0000000 Binary files a/app_local/icon.ico and /dev/null differ diff --git a/app_local/old_portable.py b/app_local/old_portable.py deleted file mode 100644 index 53ae408..0000000 --- a/app_local/old_portable.py +++ /dev/null @@ -1,350 +0,0 @@ -#pip install pyinstaller -#pyinstaller -F -i "icon.ico" portable.py -#exe into dist folder - -import numpy as np -import galois -import random -import getpass - -def main(): - safe_start() - -def safe_start(): - try: - start_menu() - except: - print("\nUnknown error, maybe ctrl+c\n") - -def start_menu(): - f = True - print("\nA soldering iron is into a black hole.") - #thermorectal cryptanalysis - if myhash(getpass.getpass("Login: ")) != 1314399736851798576: - f = False - if myhash(getpass.getpass("Password: ")) != 192441972608755898: - f = False - if f: - print("Authorization successful, wait a bit.") - menu() - else: - print("Permission denied.") - print("\nPress ENTER to exit.", end = '') - input() - -def menu(): - order = 2 ** 8 - n = order - 1 - k = 210 - #print(galois.GF(2 ** 8).properties) - GF = galois.GF(2, 8, irreducible_poly = "x^8 + x^4 + x^3 + x^2 + 1", primitive_element = "x", verify = False) - rs = galois.ReedSolomon(n, k, field = GF) - print("\nMcEliece cryptosystem implementation by vovuas2003.\n") - print("All necessary txt files must be located in the directory with this exe program.\n") - info = "Menu numbers: 0 = exit, 1 = generate keys, 2 = encrypt, 3 = decrypt,\n4 = restore pubkey, 5 = break privkey_s, 6 = break privkey_p; h = help.\n" - err = "Error! Check command info and try again!\n" - ok = "Operation successful.\n" - inp = [str(i) for i in range(7)] + ['h'] + ['1337'] - print(info) - while True: - s = input("Menu number: ") - while s not in inp: - s = input("Wrong menu number, h = help: ") - if s == 'h': - print(info) - elif s == '0': - print("\nGood luck!") - break - elif s == '1': - print("This operation will rewrite pubkey.txt, privkey_s.txt and privkey_p.txt; are you sure?") - if(not get_yes_no()): - continue - try: - generate(n, k, GF, rs) - print(ok) - except: - print(err) - elif s == '2': - print("Write your text into text.txt; pubkey.txt is required, message.txt will be rewritten.") - if(not get_yes_no()): - continue - try: - encrypt(n, k, order, GF) - print(ok) - except: - print(err) - elif s == '3': - print("You need message.txt, privkey_s.txt and privkey_p.txt; text.txt will be rewritten.") - if(not get_yes_no()): - continue - try: - decrypt(n, GF, rs) - print(ok) - except: - print(err) - elif s == '4': - print("You need privkey_s.txt and privkey_p.txt; pubkey.txt will be rewritten.") - if(not get_yes_no()): - continue - try: - restore_G_(n, GF, rs) - print(ok) - except: - print(err) - elif s == '5': - print("You need pubkey.txt and privkey_p.txt; privkey_s.txt will be rewritten.") - if(not get_yes_no()): - continue - try: - break_S(n, k, GF) - print(ok) - except: - print(err) - elif s == '6': - print("You need pubkey.txt and privkey_s.txt; privkey_p.txt will be rewritten.") - if(not get_yes_no()): - continue - try: - break_P(n, GF, rs) - print(ok) - except: - print(err) - elif s == '1337': - c = input("Move the soldering iron into the black hole number: ") - try: - PT(int(c)) - except: - print("Iron: 'I don't know this hole.'") - continue - else: - print("Impossible behaviour, mistake in source code!\nThe string allowed in the inp array is not bound to the call of any function!") - break - -def get_yes_no(): - s = input("Confirm (0 = go back, 1 = continue): ") - while s not in ['0', '1']: - s = input("Try again, 0 or 1: ") - return int(s) - -def myhash(s, m = 2**61 - 1, p = 257): - a = 0 - for i in range(len(s)): - a = ((a * p) % m + ord(s[i])) % m - return a - -def PT(m): - M = 5 - if m == 0: - print("Iron: 'OK, I will choose the number by myself.'") - while m == 0: - m = random.randint(-M, M) - s = "PT!" - p = " " - f = False - if m < 0: - s, p = p, s - m *= -1 - f = True - if m > M: - print("Iron: 'Are you sure to move me so far?'") - if(not get_yes_no()): - return - print() - if f: - print(p * (10 * m + 1)) - print(p + (s * 3 + p + s * 3 + p + s + p) * m) - print(p + (s + p + s + p * 2 + s + p * 2 + s + p) * m) - print(p + (s * 3 + p * 2 + s + p * 2 + s + p) * m) - print(p + (s + p * 4 + s + p * 4) * m) - print(p + (s + p * 4 + s + p * 2 + s + p) * m) - if f: - print(p * (10 * m + 1)) - print() - -def generate(n, k, GF, rs): - S = generate_S(k, GF) - G = rs.G - P, p = generate_P(n, GF) - G_ = S @ G @ P - write_pubkey(G_) - write_privkey(S, p) - -def generate_S(k, GF): - S = GF.Random((k, k)) - while np.linalg.det(S) == 0: - S = GF.Random((k, k)) - return S - -def generate_P(n, GF): - r = [i for i in range(n)] - p = [] - for i in range(n): - p.append(r.pop(random.randint(0, n - 1 - i))) - P = GF.Zeros((n, n)) - for i in range(n): - P[i, p[i]] = 1 - return P, p - -def write_pubkey(G_): - rows = [" ".join([str(int(cell)) for cell in row]) for row in G_] - output = "\n".join(rows) - with open("pubkey.txt", "w") as f: - f.write(output) - -def write_privkey(S, p): - output = " ".join([str(i) for i in p]) - with open("privkey_p.txt", "w") as f: - f.write(output) - rows = [" ".join([str(int(cell)) for cell in row]) for row in S] - output = "\n".join(rows) - with open("privkey_s.txt", "w") as f: - f.write(output) - -def read_pubkey(): - out = [] - tmp = [] - with open("pubkey.txt", "r") as f: - while True: - tmp = f.readline() - if not tmp: - break - out.append([int(i) for i in tmp.split()]) - return out - -def read_privkey_s(): - out = [] - tmp = [] - with open("privkey_s.txt", "r") as f: - while True: - tmp = f.readline() - if not tmp: - break - out.append([int(i) for i in tmp.split()]) - return out - -def read_privkey_p(): - with open("privkey_p.txt", "r") as f: - out = f.readline().split() - return [int(i) for i in out] - -def build_P(n, GF, p): - P = GF.Zeros((n, n)) - for i in range(n): - P[i, p[i]] = 1 - return P - -def build_P_inv(n, GF, p): - P = GF.Zeros((n, n)) - for i in range(n): - P[p[i], i] = 1 - return P - -def pad_message(msg: bytes, pad_size: int) -> list[int]: - padding = pad_size - (len(msg) % pad_size) - return list(msg + padding.to_bytes() * padding) - -def unpad_message(msg): - padding_byte = msg[-1] - for i in range(1, padding_byte + 1): - if msg[-i] != padding_byte: - print("Wrong privkey!") - raise Exception() - return msg[:-padding_byte] - -def encrypt(n, k, order, GF): - G_ = GF(read_pubkey()) - with open("text.txt", "r") as f: - text = f.read() - text = text.encode() - with open("message.txt", "w") as f: - while len(text) > k - 1: - tmp = text[: k - 1] - text = text[k - 1 :] - c = encrypt_one(n, k, order, GF, G_, tmp) - f.write(" ".join([str(i) for i in c])) - f.write("\n") - c = encrypt_one(n, k, order, GF, G_, text) - f.write(" ".join([str(i) for i in c])) - -def encrypt_one(n, k, order, GF, G_, text): - msg = pad_message(text, k) - m = GF(msg) - c = m.T @ G_ - t = (n - k) // 2 - z = np.zeros(n, dtype = int) - p = [i for i in range(n)] - for i in range(t): - ind = p.pop(random.randint(0, n - 1 - i)) - z[ind] += random.randint(1, order - 1) - z[ind] %= order - return c + GF(z) - -def decrypt(n, GF, rs): - S_inv = np.linalg.inv(GF(read_privkey_s())) - P_inv = GF(build_P_inv(n, GF, read_privkey_p())) - s = [] - with open("message.txt", "r") as inp, open("text.txt", "w") as out: - while True: - msg = inp.readline() - if not msg: - break - msg = GF(list(map(int, msg.split()))) - s += decrypt_one(rs, S_inv, P_inv, msg) - out.write(bytes(s).decode()) - -def decrypt_one(rs, S_inv, P_inv, msg): - msg = msg @ P_inv - msg, e = rs.decode(msg, errors = True) - if e == -1: - print("Too many erroneous values in message!") - raise Exception() - msg = msg @ S_inv - msg = [int(i) for i in msg] - msg = unpad_message(msg) - return msg - -def restore_G_(n, GF, rs): - S = GF(read_privkey_s()) - G = rs.G - P = GF(build_P(n, GF, read_privkey_p())) - G_ = S @ G @ P - write_pubkey(G_) - -def break_S(n, k, GF): - G_ = GF(read_pubkey()) - P_inv = GF(build_P_inv(n, GF, read_privkey_p())) - S = G_ @ P_inv - S = S[:, : k] - rows = [" ".join([str(int(cell)) for cell in row]) for row in S] - output = "\n".join(rows) - with open("privkey_s.txt", "w") as f: - f.write(output) - -def break_P(n, GF, rs): - G_ = GF(read_pubkey()) - S_inv = np.linalg.inv(GF(read_privkey_s())) - G = rs.G - G = G.T - G = [[int(i) for i in j] for j in G] - GP = S_inv @ G_ - GP = GP.T - GP = [[int(i) for i in j] for j in GP] - p = [0 for i in range(n)] - f = False - for i in range(n): - f = False - for j in range(n): - if G[i] == GP[j]: - p[i] = j - f = True - break - if f: - continue - print("Wrong pubkey and privkey_s combination!") - raise Exception() - output = " ".join([str(i) for i in p]) - with open("privkey_p.txt", "w") as f: - f.write(output) - -if __name__ == "__main__": - main() diff --git a/app_local/cryptosystem_core_v2.py b/cryptosystem_core.py similarity index 100% rename from app_local/cryptosystem_core_v2.py rename to cryptosystem_core.py diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..8809594 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +numpy +galois