在main函数中,随机生成一个16字符的密码,然后循环2022轮输出shares后的密码,直到密码正确
全局变量定义了 INT_TO_CHAR 和 CHAR_TO_INT,对应字符和索引的转换,允许的字符总共有37种
加密函数,先给密码补充16个随机字符,然后有16轮循环,每轮循环中随机生成长度为32的coeffs,然后计算对应的ffes和coeffs在模37下的乘积
coeffs(Coefficient)是多项式系数,因此这个加密过程实际上就是生成一个线性方程组,这个线性方程组有16个方程组和32个变量,解不唯一,因此不能直接解方程。在2022次循环中,x0-x15是固定的password,x16-x31是随机生成的,因此需要将随机生成的这部分给消去。我们可以将整个矩阵分为三个部分:A(16x16),B(16X16),C(16X1)。其中B矩阵是需要清除的,B是随机生成的,B为奇异矩阵的概率为1/37,在B为奇异矩阵的情况下可以求矩阵B的核(1x16),来消去B矩阵,得到新的A(1X16),C(1X1),有了16个这样的线性无关方程式后可以求出这16个解
因为连不上服务器,因此写了一个本地脚本
from sage.all import *
import ast
import string
from typing import List
from secrets import randbelow
from tqdm import tqdm
ALLOWED_CHARS = string.ascii_lowercase + string.digits + "_"
P = len(ALLOWED_CHARS)
INT_TO_CHAR = {}
CHAR_TO_INT = {}
for _i, _c in enumerate(ALLOWED_CHARS):
INT_TO_CHAR[_i] = _c
CHAR_TO_INT[_c] = _i
F = GF(P)
def get_shares(password: str, n: int, t: int) -> List[str]:
"""
Get password shares.
Args:
password: the password to be shared.
n: the number of shares returned.
t: the minimum number of shares needed to recover the password.
Returns:
the shares.
"""
assert len(password) <= t
assert n > 0
ffes = [CHAR_TO_INT[c] for c in password]
ffes += [randbelow(P) for _ in range(t - len(password))]
result = []
for _ in range(n):
coeffs = [randbelow(P) for _ in range(len(ffes))]
s = sum([x * y for x, y in zip(coeffs, ffes)]) % P
coeffs.append(s)
result.append("".join(INT_TO_CHAR[i] for i in coeffs))
return result
pw_len = 16
password = "".join(INT_TO_CHAR[randbelow(P)] for _ in range(pw_len))
while password[0] != 'a':
password = "".join(INT_TO_CHAR[randbelow(P)] for _ in range(pw_len))
print(f"生成的密码为:{password}")
n = 16
t = 32
known = []
target = []
for i in tqdm(range(2022)):
entry = get_shares(password, n, t)
mat = matrix(F, [[CHAR_TO_INT[v] for v in row] for row in entry])
A = mat[:16,:16]
B = mat[:16,16:32]
c = mat.column(-1)
if B.rank() != 16:
for ker in B.left_kernel().matrix():
known.append(ker * A)
target.append(ker * c)
print(ker * mat)
if matrix(known).rank() >= 16:
sol = matrix(F, known).solve_right(vector(F, target))
pw = "".join(INT_TO_CHAR[int(v)] for v in sol)
print("got pw!", pw)
break
else:
continue
break