diff --git a/app_local/McEliece_console.py b/app_local/McEliece_console.py index db73e5e..e211fd4 100644 --- a/app_local/McEliece_console.py +++ b/app_local/McEliece_console.py @@ -2,6 +2,7 @@ import getpass import random +import base64 def main(): safe_start() @@ -32,10 +33,10 @@ 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, h = help.\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, 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', 'h'] + ['1337'] + inp = [str(i) for i in range(7)] + ['-' + str(i) for i in range(7)] + ['c', 'b', 'h'] + ['1337', '-1337'] print(info) while True: s = input("Menu number: ") @@ -43,12 +44,21 @@ def menu(): 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.") + 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: @@ -205,9 +215,164 @@ def menu(): 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): ") diff --git a/app_local/cryptosystem_core.py b/app_local/cryptosystem_core.py index 6936317..1831431 100644 --- a/app_local/cryptosystem_core.py +++ b/app_local/cryptosystem_core.py @@ -5,6 +5,7 @@ #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 @@ -15,8 +16,9 @@ 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 and the number of erroneous bytes in the message -#see the comments below to understand the requirements for n and k +#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 @@ -127,8 +129,13 @@ def unpad_message(msg): 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)) - text = text.encode("utf-8") out = bytes() while len(text) > k - 1: tmp = text[: k - 1] @@ -137,6 +144,16 @@ def encrypt(key, text): 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) @@ -151,16 +168,6 @@ def encrypt_one(G_, text): c = c + GF(z) return bytes(c) -def 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).decode("utf-8") - return msg - def decrypt_one(S_inv, P_inv, msg): msg = msg @ P_inv msg, e = rs.decode(msg, errors = True) diff --git a/app_local/readme.txt b/app_local/readme.txt index 6ba3c73..5985c7a 100644 --- a/app_local/readme.txt +++ b/app_local/readme.txt @@ -3,7 +3,7 @@ McEliece cryptosystem implementation by vovuas2003 Required Python libraries: numpy, galois. All cryptosystem functions are implemented in cryptosystem_core.py, just import it into your project and enjoy! -For example, I coded a console menu (that works with txt files) and a GUI app. +For example, I coded a console menu (that works with text in txt files and also with any files in binary mode) and a GUI app (for text encryption). It is possible to build portable exe with pyinstaller and run code on a computer that does not have Python installed. But it is NOT compilation, so exe file will be quite large.