Compare commits
1 Commits
Author | SHA1 | Date |
---|---|---|
Naumkin Vladimir | f58c99f231 | 2 weeks ago |
@ -1,8 +0,0 @@
|
||||
FROM python:3.12-slim
|
||||
|
||||
WORKDIR /opt/McEliece
|
||||
COPY . .
|
||||
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
CMD [ "python", "McEliece_console.py" ]
|
@ -1,50 +0,0 @@
|
||||
from cryptosystem_core import *
|
||||
|
||||
def main(): #comment "return" for testing
|
||||
core = McEliece_core()
|
||||
n, k = core.get_config()
|
||||
print(n, k)
|
||||
core.change_config(5, 3) #check comments in class implementation to understand possible values
|
||||
n, k = core.get_config()
|
||||
print(n, k)
|
||||
print()
|
||||
core.generate_keys() #true random
|
||||
print(core.get_pubkey())
|
||||
print(core.get_privkey_S())
|
||||
print(core.get_privkey_p())
|
||||
print()
|
||||
core.generate_keys(sum([ord(i) for i in list("password")])) #very simple seed
|
||||
G = core.get_pubkey()
|
||||
S = core.get_privkey_S()
|
||||
p = core.get_privkey_p()
|
||||
print(G)
|
||||
print(S)
|
||||
print(p)
|
||||
print()
|
||||
core.change_config(5, 3) #unset all keys inside core
|
||||
core.set_privkey_S(S)
|
||||
core.set_privkey_p(p)
|
||||
core.restore_pubkey()
|
||||
print(core.get_pubkey() == G)
|
||||
core.change_config(5, 3) #unset all keys inside core
|
||||
core.set_pubkey(G)
|
||||
core.set_privkey_p(p)
|
||||
core.restore_privkey_S()
|
||||
print(core.get_privkey_S() == S)
|
||||
core.change_config(5, 3) #unset all keys inside core
|
||||
core.set_pubkey(G)
|
||||
core.set_privkey_S(S)
|
||||
core.restore_privkey_p()
|
||||
print(core.get_privkey_p() == p)
|
||||
print()
|
||||
for j in range(2):
|
||||
text = [i + 1 for i in range(5)]
|
||||
msg = core.encrypt(text)
|
||||
print(msg)
|
||||
text = core.decrypt(msg)
|
||||
print(text)
|
||||
print()
|
||||
print("All tests are finished!")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -1,15 +0,0 @@
|
||||
McEliece cryptosystem implementation by vovuas2003
|
||||
|
||||
Required Python libraries: numpy, galois.
|
||||
|
||||
UPDATE: version 2 is available. Check cryptosystem_core_v2 and McEliece_console_v2.
|
||||
|
||||
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 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.
|
||||
|
||||
The pdf presentation in Russian contains a bit of theory about the Mceliece cryptosystem.
|
||||
icon.ico is an optional file for pyinstaller
|
||||
old_portable.py can support another order of galois field, but saves raw integers and does not specify utf-8 encoding for strings and txt files
|
Binary file not shown.
@ -0,0 +1,130 @@
|
||||
#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()
|
@ -0,0 +1,445 @@
|
||||
#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()
|
@ -0,0 +1,246 @@
|
||||
#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()
|
@ -0,0 +1,92 @@
|
||||
import numpy as np
|
||||
import galois
|
||||
import random
|
||||
import getpass
|
||||
import hashlib
|
||||
import pyperclip
|
||||
|
||||
def main():
|
||||
try:
|
||||
menu()
|
||||
except:
|
||||
print("Error!")
|
||||
|
||||
def menu():
|
||||
core = McEliece_core()
|
||||
core.generate_keys(normalhash(getpass.getpass("Password: ")))
|
||||
pyperclip.copy(bytes(core.decrypt([int(i) for i in read_file("only_password")])).decode('utf-8'))
|
||||
print("OK!")
|
||||
|
||||
class McEliece_core:
|
||||
def __init__(self):
|
||||
self._order = 256
|
||||
self._n = 255
|
||||
self._k = 210
|
||||
self._GF = galois.GF(2, 8, irreducible_poly = "x^8 + x^4 + x^3 + x^2 + 1", primitive_element = "x", verify = False)
|
||||
self._rs = galois.ReedSolomon(self._n, self._k, field = self._GF)
|
||||
self._G = self._GF.Zeros((self._k, self._n))
|
||||
self._S = self._GF.Zeros((self._k, self._k))
|
||||
self._S_inv = self._GF.Zeros((self._k, self._k))
|
||||
self._P = self._GF.Zeros((self._n, self._n))
|
||||
self._P_inv = self._GF.Zeros((self._n, self._n))
|
||||
self._p = [0 for i in range(self._n)]
|
||||
def generate_keys(self, seed):
|
||||
seed %= 2**32
|
||||
self._unsafe_generate_S(seed)
|
||||
self._unsafe_generate_P(seed)
|
||||
self._G = self._S @ self._rs.G @ self._P
|
||||
def decrypt(self, msg):
|
||||
try:
|
||||
msg = [msg[i - self._n : i] for i in range(self._n, len(msg) + self._n, self._n)]
|
||||
msg = [self._decrypt_one(self._GF(i)) for i in msg]
|
||||
return [i for j in msg for i in j]
|
||||
except:
|
||||
raise
|
||||
def _unsafe_generate_S(self, seed):
|
||||
pseudo = np.random.RandomState(seed)
|
||||
S = self._GF(pseudo.randint(0, self._order, (self._k, self._k)))
|
||||
while np.linalg.det(S) == 0:
|
||||
S = self._GF(pseudo.randint(0, self._order, (self._k, self._k)))
|
||||
self._S = S
|
||||
self._S_inv = np.linalg.inv(S)
|
||||
def _unsafe_generate_P(self, seed):
|
||||
pseudo = np.random.RandomState(seed)
|
||||
p = [i for i in range(self._n)]
|
||||
pseudo.shuffle(p)
|
||||
self._p = p
|
||||
self._P = self._GF.Zeros((self._n, self._n))
|
||||
self._P_inv = self._GF.Zeros((self._n, self._n))
|
||||
for i in range(self._n):
|
||||
self._P[i, p[i]] = 1
|
||||
self._P_inv[p[i], i] = 1
|
||||
def _decrypt_one(self, msg):
|
||||
msg = msg @ self._P_inv
|
||||
msg, e = self._rs.decode(msg, errors = True)
|
||||
if e == -1:
|
||||
raise Exception()
|
||||
msg = msg @ self._S_inv
|
||||
msg = [int(i) for i in msg]
|
||||
try:
|
||||
msg = self._unpad_message(msg)
|
||||
except:
|
||||
raise
|
||||
return msg
|
||||
def _unpad_message(self, msg):
|
||||
last_value = msg[-1]
|
||||
if last_value >= self._k or last_value <= 0:
|
||||
raise Exception()
|
||||
for i in range(1, last_value + 1):
|
||||
if msg[-i] != last_value:
|
||||
raise Exception()
|
||||
return msg[: -last_value]
|
||||
|
||||
def read_file(name):
|
||||
with open(name, "rb") as f:
|
||||
data = f.read()
|
||||
return data
|
||||
|
||||
def normalhash(s):
|
||||
return int(hashlib.sha256(bytearray(s, 'utf-8')).hexdigest(), 16)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
@ -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()
|
@ -0,0 +1,249 @@
|
||||
import numpy as np
|
||||
import galois
|
||||
import random
|
||||
import getpass
|
||||
import hashlib
|
||||
import pyperclip
|
||||
|
||||
def main():
|
||||
try:
|
||||
menu()
|
||||
except:
|
||||
print("\nUnknown error (maybe ctrl+c), emergency exit!")
|
||||
|
||||
def menu():
|
||||
info = "Menu numbers: h = info, t = test clipboard, c = config;\n0 = exit, 1 = generate, 2 = encrypt, 3 = decrypt\n"
|
||||
err = "Error, try again!\n"
|
||||
ok = "Operation successful.\n"
|
||||
inp = ['h', 'c', 't'] + [str(i) for i in range (4)] + ['1337']
|
||||
core = McEliece_core()
|
||||
print("\nMcEliece password encryption by vovuas2003.\n")
|
||||
print(info)
|
||||
while True:
|
||||
s = input("Menu number: ")
|
||||
while s not in inp:
|
||||
s = input("Wrong menu number; h = help: ")
|
||||
if s == '0':
|
||||
print("\nGood luck!")
|
||||
break
|
||||
elif s == 'h':
|
||||
print(info)
|
||||
elif s == 't':
|
||||
print("Do you want to check Python ability to use clipboard in your OS?")
|
||||
if(not get_yes_no()):
|
||||
continue
|
||||
try:
|
||||
print('Trying to write "Hello, world!" to clipboard.')
|
||||
mycopy("Hello, world!")
|
||||
print("Success! You can check ctrl+v.")
|
||||
except:
|
||||
print("Python cannot use clipboard. On Linux maybe you need to run command: sudo apt-get install xclip.\nOr try code below to check python error log:\nimport pyperclip #don't forget to pip install pyperclip\npyperclip.copy(\"Hello, world!\")")
|
||||
elif s == 'c':
|
||||
n, k = core.get_config()
|
||||
print("Default config is 255 210, current is " + str(n) + " " + str(k) + ". Change config? Also reset all keys!")
|
||||
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).")
|
||||
n, k = map(int, input("Write n and k separated by a space: ").split())
|
||||
core.change_config(n, k)
|
||||
print(ok)
|
||||
except:
|
||||
print(err)
|
||||
elif s == '1':
|
||||
print("Reset all keys!")
|
||||
if(not get_yes_no()):
|
||||
continue
|
||||
try:
|
||||
core.generate_keys(normalhash(getpass.getpass("Password for hash: ")))
|
||||
print(ok)
|
||||
except:
|
||||
print(err)
|
||||
elif s == '2':
|
||||
print("Encrypt hided input (ONLY ONE LINE!!!) from clipboard!")
|
||||
if(not get_yes_no()):
|
||||
continue
|
||||
try:
|
||||
inp_str = getpass.getpass("Hided string to encrypt: ")
|
||||
out_name = input("Filename to save: ")
|
||||
if not out_name:
|
||||
print("Using default name ciphered_string.bin")
|
||||
out_name = "ciphered_string.bin"
|
||||
write_file(out_name, bytes(core.encrypt([int(i) for i in inp_str.encode('utf-8')])))
|
||||
print(ok)
|
||||
except:
|
||||
print(err)
|
||||
elif s == '3':
|
||||
print("Decrypt string from file and copy to clipboard!")
|
||||
if(not get_yes_no()):
|
||||
continue
|
||||
try:
|
||||
inp_name = input("Filename to decrypt: ")
|
||||
if not inp_name:
|
||||
print("Using default name ciphered_string.bin")
|
||||
inp_name = "ciphered_string.bin"
|
||||
mycopy(bytes(core.decrypt([int(i) for i in read_file(inp_name)])).decode('utf-8'))
|
||||
print(ok)
|
||||
except:
|
||||
print(err)
|
||||
elif s == '1337':
|
||||
mycopy(PT())
|
||||
else:
|
||||
print("Impossible behaviour, mistake in source code, emergency exit!\nThe string allowed in the inp array is not bound to the call of any function!")
|
||||
break
|
||||
|
||||
class McEliece_core:
|
||||
def __init__(self):
|
||||
self._order = 256
|
||||
self._n = 255
|
||||
self._k = 210
|
||||
self._t = (self._n - self._k) // 2
|
||||
self._GF = galois.GF(2, 8, irreducible_poly = "x^8 + x^4 + x^3 + x^2 + 1", primitive_element = "x", verify = False)
|
||||
self._rs = galois.ReedSolomon(self._n, self._k, field = self._GF)
|
||||
self._G = self._GF.Zeros((self._k, self._n))
|
||||
self._S = self._GF.Zeros((self._k, self._k))
|
||||
self._S_inv = self._GF.Zeros((self._k, self._k))
|
||||
self._P = self._GF.Zeros((self._n, self._n))
|
||||
self._P_inv = self._GF.Zeros((self._n, self._n))
|
||||
self._p = [0 for i in range(self._n)]
|
||||
def change_config(self, n, k):
|
||||
try:
|
||||
if k < 2:
|
||||
raise Exception()
|
||||
rs = galois.ReedSolomon(n, k, field = self._GF)
|
||||
except:
|
||||
raise
|
||||
else:
|
||||
self._n = n
|
||||
self._k = k
|
||||
self._t = (n - k) // 2
|
||||
self._rs = rs
|
||||
self._G = self._GF.Zeros((self._k, self._n))
|
||||
self._S = self._GF.Zeros((self._k, self._k))
|
||||
self._S_inv = self._GF.Zeros((self._k, self._k))
|
||||
self._P = self._GF.Zeros((self._n, self._n))
|
||||
self._P_inv = self._GF.Zeros((self._n, self._n))
|
||||
self._p = [0 for i in range(self._n)]
|
||||
def get_config(self):
|
||||
return self._n, self._k
|
||||
def generate_keys(self, seed):
|
||||
seed %= 2**32
|
||||
self._unsafe_generate_S(seed)
|
||||
self._unsafe_generate_P(seed)
|
||||
self._G = self._S @ self._rs.G @ self._P
|
||||
def encrypt(self, text):
|
||||
try:
|
||||
out = []
|
||||
while len(text) > self._k - 1:
|
||||
tmp = text[: self._k - 1]
|
||||
text = text[self._k - 1 :]
|
||||
out += self._encrypt_one(tmp)
|
||||
out += self._encrypt_one(text)
|
||||
return out
|
||||
except:
|
||||
raise
|
||||
def decrypt(self, msg):
|
||||
try:
|
||||
msg = [msg[i - self._n : i] for i in range(self._n, len(msg) + self._n, self._n)]
|
||||
msg = [self._decrypt_one(self._GF(i)) for i in msg]
|
||||
return [i for j in msg for i in j]
|
||||
except:
|
||||
raise
|
||||
def _unsafe_generate_S(self, seed):
|
||||
pseudo = np.random.RandomState(seed)
|
||||
S = self._GF(pseudo.randint(0, self._order, (self._k, self._k)))
|
||||
while np.linalg.det(S) == 0:
|
||||
S = self._GF(pseudo.randint(0, self._order, (self._k, self._k)))
|
||||
self._S = S
|
||||
self._S_inv = np.linalg.inv(S)
|
||||
def _unsafe_generate_P(self, seed):
|
||||
pseudo = np.random.RandomState(seed)
|
||||
p = [i for i in range(self._n)]
|
||||
pseudo.shuffle(p)
|
||||
self._p = p
|
||||
self._P = self._GF.Zeros((self._n, self._n))
|
||||
self._P_inv = self._GF.Zeros((self._n, self._n))
|
||||
for i in range(self._n):
|
||||
self._P[i, p[i]] = 1
|
||||
self._P_inv[p[i], i] = 1
|
||||
def _encrypt_one(self, text):
|
||||
msg = self._pad_message(text)
|
||||
m = self._GF(msg)
|
||||
c = m.T @ self._G
|
||||
z = np.zeros(self._n, dtype = int)
|
||||
p = [i for i in range(self._n)]
|
||||
for i in range(self._t):
|
||||
ind = p.pop(random.randint(0, self._n - 1 - i))
|
||||
z[ind] = random.randint(1, self._order - 1)
|
||||
c = c + self._GF(z)
|
||||
return [int(i) for i in c]
|
||||
def _decrypt_one(self, msg):
|
||||
msg = msg @ self._P_inv
|
||||
msg, e = self._rs.decode(msg, errors = True)
|
||||
if e == -1:
|
||||
raise Exception()
|
||||
msg = msg @ self._S_inv
|
||||
msg = [int(i) for i in msg]
|
||||
try:
|
||||
msg = self._unpad_message(msg)
|
||||
except:
|
||||
raise
|
||||
return msg
|
||||
def _pad_message(self, msg):
|
||||
last_value = self._k - (len(msg) % self._k)
|
||||
return msg + [last_value] * last_value
|
||||
def _unpad_message(self, msg):
|
||||
last_value = msg[-1]
|
||||
if last_value >= self._k or last_value <= 0:
|
||||
raise Exception()
|
||||
for i in range(1, last_value + 1):
|
||||
if msg[-i] != last_value:
|
||||
raise Exception()
|
||||
return msg[: -last_value]
|
||||
|
||||
def write_file(name, data):
|
||||
with open(name, "wb") as f:
|
||||
f.write(data)
|
||||
|
||||
def read_file(name):
|
||||
with open(name, "rb") as f:
|
||||
data = f.read()
|
||||
return data
|
||||
|
||||
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 normalhash(s):
|
||||
return int(hashlib.sha256(bytearray(s, 'utf-8')).hexdigest(), 16)
|
||||
|
||||
def PT(m = -3, M = 3):
|
||||
if m == 0 or abs(m) > M:
|
||||
return "PT!"
|
||||
s = "PT!"
|
||||
p = " "
|
||||
f = False
|
||||
if m < 0:
|
||||
s, p = p, s
|
||||
m *= -1
|
||||
f = True
|
||||
out = "\n"
|
||||
if f:
|
||||
out += p * (10 * m + 1) + "\n"
|
||||
out += p + (s * 3 + p + s * 3 + p + s + p) * m + "\n"
|
||||
out += p + (s + p + s + p * 2 + s + p * 2 + s + p) * m + "\n"
|
||||
out += p + (s * 3 + p * 2 + s + p * 2 + s + p) * m + "\n"
|
||||
out += p + (s + p * 4 + s + p * 4) * m + "\n"
|
||||
out += p + (s + p * 4 + s + p * 2 + s + p) * m + "\n"
|
||||
if f:
|
||||
out += p * (10 * m + 1) + "\n"
|
||||
out += "\n"
|
||||
return out
|
||||
|
||||
def mycopy(s):
|
||||
pyperclip.copy(s)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
@ -0,0 +1,5 @@
|
||||
McEliece cryptosystem implementation by vovuas2003
|
||||
|
||||
Required additional Python libraries: numpy, galois (numpy extension).
|
||||
|
||||
Version 2 is the latest. Check cryptosystem_core_v2 and McEliece_console_v2.
|
@ -1,2 +0,0 @@
|
||||
numpy
|
||||
galois
|
Loading…
Reference in New Issue