From 53baea339b0b69e48a43898b4ffbb3cf7ee413fa Mon Sep 17 00:00:00 2001 From: Naumkin Vladimir Date: Tue, 16 Apr 2024 23:36:59 +0300 Subject: [PATCH] Add portable version --- app_local/portable.py | 350 ++++++++++++++++++++++++++++++++++++++++++ app_local/readme.txt | 8 +- 2 files changed, 357 insertions(+), 1 deletion(-) create mode 100644 app_local/portable.py diff --git a/app_local/portable.py b/app_local/portable.py new file mode 100644 index 0000000..53ae408 --- /dev/null +++ b/app_local/portable.py @@ -0,0 +1,350 @@ +#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/readme.txt b/app_local/readme.txt index 6e21f35..af6f503 100644 --- a/app_local/readme.txt +++ b/app_local/readme.txt @@ -1,5 +1,7 @@ McEliece cryptosystem implementation +Update: portable version is available! All functions in one file. New features and some improvements! + Usage: 0. pip install numpy and galois 1. generate.py - generate and save public and private keys @@ -10,4 +12,8 @@ Usage: Hacker can get your private key if he will know a half of it (and pubkey.py, decode.py and Reed-Solomon algo). Check break.py to understand how hacker can do this. -Notice: left part of G is E, because we use Reed-Solomon algo; so left part of S @ G is S and cutting right colomns works; my_fix(G) returns E and in break_S we needn't get inv(G), just S = my_fix(G_ @ inv(P)); try break_S with another (not Reed-Solomon) code (matrix G will be different; will my_fix(G) and my_fix(G_) return nonsingular matrices?; of course, rank(G) = rank(G_) = k and we can iterate through all possible combinations of column deletions and find one that does not lead to nonsingular matrices); another way to get S is calculating it row by row (solving k systems, each has n equations with k variables, k < n, but we need to do it in Galois Field). +todo: +0. build portable exe with pyinstaller +1. left part of G is E, because we use Reed-Solomon algo; so left part of S @ G is S and cutting right colomns works; my_fix(G) returns E and in break_S we needn't get inv(G), just S = my_fix(G_ @ inv(P)); try break_S with another (not Reed-Solomon) code (matrix G will be different; will my_fix(G) and my_fix(G_) return nonsingular matrices?; of course, rank(G) = rank(G_) = k and we can iterate through all possible combinations of column deletions and find one that does not lead to nonsingular matrices); another way to get S is calculating it row by row (solving k systems, each has n equations with k variables, k < n, but we need to do it in Galois Field) +2. DONE! check randomization during encode (add vector z, check https://en.wikipedia.org/wiki/McEliece_cryptosystem) +3. DONE! make presentation that explains McEliece cryptosystem