You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

351 lines
10 KiB
Python

#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()