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.
93 lines
3.1 KiB
Python
93 lines
3.1 KiB
Python
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()
|