被一个小题整坏了,后边就没认真打。赛后把没作的复盘一下。
比赛有52个应急响应,猜是取证,都是队友在干,我也不大关心。前边大多题是比赛的原题。这是后来听说的,可都没见过,看来打的比赛还是少了。
Crypto
peeeq
这个题始终不明白什么意思,后来看WP,才大概明白。
题目唯一的提示是leak,而这个leak又与谁都没关系。assert看不明白,后来给了提示说是assert不对。
看WP其实是说leak为一个最小值,这些值都可以表示为k1p+k2q的形式。而这个最小值叫最大不可能K,从形式上猜跟φ有关。WP上说是φ-1,那就好办了。
import gmpy2
from Crypto.Util.number import *
def check(m, p, q):
if m == 0: return True
if m >= p and check(m-p, p, q) : return True
if m >= q and check(m-q, p, q) : return True
return False
flag = b"paluctf{***********************}"
p = getPrime(1024)
q = getPrime(1024)
e = getPrime(17)
n = p*q
pinv_e = gmpy2.invert(p, q)*e
qinv_e = gmpy2.invert(q, p)*e
m = bytes_to_long(flag)
c = pow(m, e, n)
print(c)
print(pinv_e)
print(qinv_e)
m = 0
while True:
assert m <= leak or check(m, p, q)
m += 1
leak = 20650913970072868759959272239604024297420806808659110564312051736808778949599012338389873196411652566474168134639876252857623310159737758732845898956842366935678501021994729279299799994075598575657211550223683499328614158165787416177094173112167115888930719187253398687736037116845083325669521670262760600243895871953940839864925909273175442587377607028910874730344252804963645659770898616148180806608083557249713184454706023876544328444568520666837841566163924062054001534893538655581481021600384148478571641075265311650046699619525464106135807483192890198614434965478741402348088647355476402189540171838712520668315
c = 14656499683788461319601710088831412892194505254418064899761498679297764485273476341077222358310031603834624959088854557947176472443021560072783573052603773463734827298069959304747376040480522193600487999140388188743055733577433643210327070027972481119823973316743393323273128561824747871183252082782459568278265418266528855123687868624734106855360408027492126167597948385055908257193701028960507382053300960017612431744000472268868103779169759349652561826935960615964589526055579319224213399173783902104833907847546751649110661705034653912439791460180154034041113546810232929706136321281991114377628823527206109309013
pinv_e = 12474140378771043865022148848078136936465079800066130234618983104385642778672967864991495110508733111980066517889153671507701349679185396054215439179349403857665966245686661757089470553109534987101888628107055364941617805783362125836104920292552457095662777743387917809524955960583091720618281570118299619677634759
qinv_e = 1647206449953560407401595632741127506095799998014240087894866808907042944168674423038307995055460808040825182837354682801054048594394389801771888111156812819183105159993880849157459496014737241461466870906700457127028184554416373467332704931423207098246831148428600375416541264997943693621557486559170922000282251
'''
题目描述有误 assert m <= leak or check(m, p, q) 中的leak为满足要求的最小值
对于 m > {x | x>=leak} 的 m 都必然满足 check(m, p, q) == True
'''
对于已知φ和伪逆的情况可以用z3直接解。
1,这里e未知,可以直接用gcd求出再分解一下找17位的素数。
2,列两个算式求解:n=pinv*p + qinv*q -1;phi = (p-1)*(q-1)
#factor(gcd(pinv_e,qinv_e))
#3 * 102563
e = 102563
pinv,qinv = pinv_e//e,qinv_e//e
#最大不可能K=mp+nq 使>=K的值都能表示为mp+nq K=pq-p-q = phi-1
phi = leak+1
import z3
import libnum
s = z3.Solver()
p, q = z3.Ints('p q')
#invp*p = 1 mod q ; invq*q = 1 mod p
#????
s.add(p*q == pinv * p + qinv * q - 1)
s.add(phi == (p-1)*(q-1))
print(s.check())
m = s.model()
p = m[p].as_long()
q = m[q].as_long()
from Crypto.Util.number import *
m = pow(c,inverse(e,p-1),p)
long_to_bytes(m)
#b'paluctf{51b98a17-6843-4e3b-b06c-3cd956bc944c}'
gcccd
第2个题就比较简单了,给了c1 = m^e mod n; c2 = (m//2)^e mod n
from Crypto.Util.number import getStrongPrime, GCD, bytes_to_long
import os
from flag import flag
def long_to_bytes(long_int, block_size=None):
"""Convert a long integer to bytes, optionally right-justified to a given block size."""
bytes_data = long_int.to_bytes((long_int.bit_length() + 7) // 8, 'big')
return bytes_data if not block_size else bytes_data.rjust(block_size, b'\x00')
def gen_keys(bits=512, e=5331):
"""Generate RSA modulus n and public exponent e such that GCD((p-1)*(q-1), e) == 1."""
while True:
p, q = getStrongPrime(bits), getStrongPrime(bits)
n = p * q
if GCD((p-1) * (q-1), e) == 1:
return n, e
def pad(m, n):
"""Pad the message m for RSA encryption under modulus n using PKCS#1 type 1."""
mb, nb = long_to_bytes(m), long_to_bytes(n)
assert len(mb) <= len(nb) - 11
padding = os.urandom(len(nb) - len(mb) - 3).replace(b'\x01', b'')
return bytes_to_long(b'\x00\x01' + padding + b'\x00' + mb)
def encrypt(m, e, n):
"""Encrypt message m with RSA public key (e, n)."""
return pow(m, e, n)
n, e = gen_keys()
m = pad(bytes_to_long(flag), n)
c1, c2 = encrypt(m, e, n), encrypt(m // 2, e, n)
print(f"n = {n}\ne = {e}\nc1 = {c1}\nc2 = {c2}")
n = 128134155200900363557361770121648236747559663738591418041443861545561451885335858854359771414605640612993903005548718875328893717909535447866152704351924465716196738696788273375424835753379386427253243854791810104120869379525507986270383750499650286106684249027984675067236382543612917882024145261815608895379
e = 5331
c1 = 60668946079423190709851484247433853783238381043211713258950336572392573192737047470465310272448083514859509629066647300714425946282732774440406261265802652068183263460022257056016974572472905555413226634497579807277440653563498768557112618320828785438180460624890479311538368514262550081582173264168580537990
c2 = 43064371535146610786202813736674368618250034274768737857627872777051745883780468417199551751374395264039179171708712686651485125338422911633961121202567788447108712022481564453759980969777219700870458940189456782517037780321026907310930696608923940135664565796997158295530735831680955376342697203313901005151
由于flag以“}”结尾所在m是奇数,所以列式子的时候列成:
c1 = (2M+1)^e ,c2 = M^e然后用HGCD求解,原来一直用短填充,但用HGCD更快。反正都是模板。
from Crypto.Util.number import *
#half-gcd算法
def HGCD(a, b):
if 2 * b.degree() <= a.degree() or a.degree() == 1:
return 1, 0, 0, 1
m = a.degree() // 2
a_top, a_bot = a.quo_rem(x^m)
b_top, b_bot = b.quo_rem(x^m)
R00, R01, R10, R11 = HGCD(a_top, b_top)
c = R00 * a + R01 * b
d = R10 * a + R11 * b
q, e = c.quo_rem(d)
d_top, d_bot = d.quo_rem(x^(m // 2))
e_top, e_bot = e.quo_rem(x^(m // 2))
S00, S01, S10, S11 = HGCD(d_top, e_top)
RET00 = S01 * R00 + (S00 - q * S01) * R10
RET01 = S01 * R01 + (S00 - q * S01) * R11
RET10 = S11 * R00 + (S10 - q * S11) * R10
RET11 = S11 * R01 + (S10 - q * S11) * R11
return RET00, RET01, RET10, RET11
def GCD(a, b):
print(a.degree(), b.degree())
q, r = a.quo_rem(b)
if r == 0: