MiniL Crypto 复现

Curvesignin Revenge

题目如下

from random import randint
from os import urandom
from collections import namedtuple
from hashlib import sha256

from Crypto.Cipher import AES
from Crypto.Util.number import long_to_bytes
from Crypto.Util.Padding import pad
from secret import FLAG


Point = namedtuple("Point", "x y")


def add(P, Q):
    Px, Py = P.x, P.y
    Qx, Qy = Q.x, Q.y
    Rx = (Px*Qx-e*Py*Qy) % N
    Ry = (Px*Qy+Py*Qx) % N
    return Point(Rx ,Ry)


def mul(P, exp):
    Q = Point(1, 0)
    while exp > 0:
        if exp & 1:
            Q = add(Q, P)
        P = add(P, P)
        exp >>= 1
    return Q


def gen_key():
    private_key = randint(1, N)
    public_key = mul(G, private_key)
    return (public_key, private_key)


def share_secret(P, d):
    return mul(P, d).x


def encrypt(share_secret, flag):
    key = sha256(long_to_bytes(share_secret)).digest()[:16]
    iv = urandom(16)
    cipher = AES.new(key, AES.MODE_CBC, iv)
    ciphertext = cipher.encrypt(pad(flag,16))
    data = {"iv":iv.hex(),"encrypt_flag":ciphertext.hex()}
    return data


N = 61820395509869592945047899644070363303060865412602815892951881829112472104091
e = 133422
G = Point(37234080987968345210046814543941568534026683208134935256498818666416936228347,23681207802011885401101067347527183297441941230486570817545706194562153385116)
Alice_pub, n_a = gen_key()
Bob_pub, n_b = gen_key()
assert (Alice_pub.x**2 + e*Alice_pub.y**2) % N == 1
assert (Bob_pub.x**2 + e*Bob_pub.y**2) % N == 1

print(f"Alice's public key: {Alice_pub}")
print(f"Bob's public key: {Bob_pub}")

share = share_secret(Bob_pub, n_a)
enc = encrypt(share, FLAG)

print(f'Encrypted flag: {enc}')

Enc、Alice/Bob 's public key 都已知 分析下来 就是(a_p,a_s)=k(G_p,G_s) 已知a_p G 求a_s 即求k
就是DLP 但是还是不太会啊。。
看了一个师傅的wp如下:
这是个cyclic group,群的阶为N+1, 生成元是G,可以观察到N+1是一个光滑数,所以我们考虑$$PH+bsgs+crt$$
求一下n_a

from sage.rings import integer_ring
from collections import namedtuple
from hashlib import sha256

from Crypto.Cipher import AES
from Crypto.Util.number import long_to_bytes

Point = namedtuple("Point", "x y")
G = Point(37234080987968345210046814543941568534026683208134935256498818666416936228347,23681207802011885401101067347527183297441941230486570817545706194562153385116)
N = 61820395509869592945047899644070363303060865412602815892951881829112472104091
e = 133422


def add(P, Q):
    Px, Py = P.x, P.y
    Qx, Qy = Q.x, Q.y
    Rx = (Px*Qx-e*Py*Qy) % N
    Ry = (Px*Qy+Py*Qx) % N
    return Point(Rx ,Ry)


def mul(P, exp):
    Q = Point(1, 0)
    while exp > 0:
        if exp & 1:
            Q = add(Q, P)
        P = add(P, P)
        exp >>= 1
    return Q


Z = integer_ring.ZZ
def bsgs_alg(a, b, bounds):

    identity = Point(x = 1 , y = 0)
    lb, ub = bounds
    if lb < 0 or ub < lb:
        raise ValueError("bsgs() requires 0<=lb<=ub")

    ran = 1 + ub - lb   # the length of the interval
    # c = op(inverse(b), multiple(a, lb, operation=operation))
    c = add(mul(b , N), mul(a , lb))

    if ran < 30:    # use simple search for small ranges  
        d = c
        for i0 in range(ran):
            i = lb + i0
            if d == identity:        # identity == b^(-1)*a^i, so return i
                return Z(i)
            d = add(a, d)
        raise ValueError("No solution in bsgs()")

    m = ran.isqrt() + 1  # we need sqrt(ran) rounded up
    table = dict()       # will hold pairs (a^(lb+i),lb+i) for i in range(m)

    d = c
    for i0 in xsrange(m):
        i = lb + i0
        if d == identity:        # identity == b^(-1)*a^i, so return i
            return Z(i)
        table[d] = i
        d = add(d, a)

    c = add(c, mul(d , N))     # this is now a**(-m)
    d = identity
    for i in xsrange(m):
        j = table.get(d)
        if j is not None:  # then d == b*a**(-i*m) == a**j
            return Z(i * m + j)
        d = add(c, d)
    
    raise ValueError("Log of %s to the base %s does not exist in %s." % (b, a, bounds))
   

def discrete_log_new(a, base = G, ord=N + 1):
    try:
        f = factor(ord)
        f = list(f)
        # print(f)
        l = [0] * len(f)
        for i, (pi, ri) in enumerate(f):
            for j in range(ri):
                c = bsgs_alg(mul(base , (ord // pi)),
                            mul((add(a ,  mul(base , l[i]*N))) , (ord // pi**(j + 1))),
                            (0, pi))
                l[i] += c * (pi**j)
        from sage.arith.all import CRT_list
        return CRT_list(l, [pi**ri for pi, ri in f])
    except ValueError:
        raise ValueError("No discrete log of %s found to base %s" % (a, base))
Alice=Point(53887628258266977236946886765125225993985116834354341126233510219966071523616, 28158965058787630555744590318664291139012897721840003355218563579301165856248)
n_a= discrete_log_new(Alice, G , N+1)
print(n_a)
#47885227719229463949869731721047296800235918311075465323872183842041075747873

然后代回去用密钥解即可

from hashlib import sha256
from collections import namedtuple
from Crypto.Cipher import AES
from Crypto.Util.number import *
Point = namedtuple("Point", "x y")

def add(P, Q):
    Px, Py = P.x, P.y
    Qx, Qy = Q.x, Q.y
    Rx = (Px*Qx-e*Py*Qy) % N
    Ry = (Px*Qy+Py*Qx) % N
    return Point(Rx ,Ry)


def mul(P, exp):
    Q = Point(1, 0)
    while exp > 0:
        if exp & 1:
            Q = add(Q, P)
        P = add(P, P)
        exp >>= 1
    return Q


def gen_key():
    private_key = randint(1, N)
    public_key = mul(G, private_key)
    return (public_key, private_key)


def share_secret(P, d):
    return mul(P, d).x
def decrypt(share_secret, enc_flag,iv):
    key = sha256(long_to_bytes(share_secret)).digest()[:16]
    cipher = AES.new(key, AES.MODE_CBC, iv)
    flag= cipher.decrypt(enc_flag)
    return flag
e = 133422
N = 61820395509869592945047899644070363303060865412602815892951881829112472104091
G = Point(37234080987968345210046814543941568534026683208134935256498818666416936228347,23681207802011885401101067347527183297441941230486570817545706194562153385116)
n_a=47885227719229463949869731721047296800235918311075465323872183842041075747873
Bob_pub=Point(34916507512495859038246013669842835077935990837718819374050138139835873991114, 17695334453582551266443068581568418621987401844207090836349323784243222912322)
share = share_secret(Bob_pub, n_a)
iv=bytes.fromhex("aa4b4d17e2227752b79a811669915786")
encrypt_flag=bytes.fromhex("a4923a789d1ebe2a84c300bcf38dd564250089746a84509360ec8b728ecadac2fa5cd26bfdef00d26f8e6d2fcc4e6a00")
print(decrypt(share,encrypt_flag,iv))
#b'miniLCTF{C0nics_ar3_n0t_elliptic_Curv3s!}\x07\x07\x07\x07\x07\x07\x07'

这也就是官方wp中说的Pohlig-Hellman 算法 后续再深入学习一下这个算法
其他题懒得写wp再更新

posted @ 2024-05-15 12:14  srf27  阅读(33)  评论(0)    收藏  举报