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再更新

浙公网安备 33010602011771号