0
点赞
收藏
分享

微信扫一扫

TetCTF 2022 Crypto shares writeup

兮城 2022-01-08 阅读 64

在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
举报

相关推荐

0 条评论