NewStarCTF Crypto
Week1
除了那个babyencoding第三个没看出uuencode外其余都没什么问题
这里只写非简单题
Vigenère
这里有个注意点 解密语言要选西班牙语(好像是) 反正要试一试就行了
babyencoding
前两个用 cyberchef秒解 第三个是uuencode 用https://ctf.bugku.com/tool/uuencode
Small d
维纳攻击 脚本:
点击查看代码
# 维纳攻击
import gmpy2
import primefac
from Crypto.Util.number import *
def transform(x,y): #使用辗转相处将分数 x/y 转为连分数的形式
res=[]
while y:
res.append(x//y)
x,y=y,x%y
return res
def continued_fraction(sub_res):
numerator,denominator=1,0
for i in sub_res[::-1]: #从sublist的后面往前循环
denominator,numerator=numerator,i*numerator+denominator
return denominator,numerator #得到渐进分数的分母和分子,并返回
#求解每个渐进分数
def sub_fraction(x,y):
res=transform(x,y)
res=list(map(continued_fraction,(res[0:i] for i in range(1,len(res))))) #将连分数的结果逐一截取以求渐进分数
return res
def get_pq(a,b,c): #由p+q和pq的值通过维达定理来求解p和q
par=gmpy2.isqrt(b*b-4*a*c) #由上述可得,开根号一定是整数,因为有解
x1,x2=(-b+par)//(2*a),(-b-par)//(2*a)
return x1,x2
def wienerAttack(e,n):
for (d,k) in sub_fraction(e,n): #用一个for循环来注意试探e/n的连续函数的渐进分数,直到找到一个满足条件的渐进分数
if k==0: #可能会出现连分数的第一个为0的情况,排除
continue
if (e*d-1)%k!=0: #ed=1 (mod φ(n)) 因此如果找到了d的话,(ed-1)会整除φ(n),也就是存在k使得(e*d-1)//k=φ(n)
continue
phi=(e*d-1)//k #这个结果就是 φ(n)
px,qy=get_pq(1,n-phi+1,n)
if px*qy==n:
p,q=abs(int(px)),abs(int(qy)) #可能会得到两个负数,负负得正未尝不会出现
d=gmpy2.invert(e,(p-1)*(q-1)) #求ed=1 (mod φ(n))的结果,也就是e关于 φ(n)的乘法逆元d
return d
print("该方法不适用")
c = 6755916696778185952300108824880341673727005249517850628424982499865744864158808968764135637141068930913626093598728925195859592078242679206690525678584698906782028671968557701271591419982370839581872779561897896707128815668722609285484978303216863236997021197576337940204757331749701872808443246927772977500576853559531421931943600185923610329322219591977644573509755483679059951426686170296018798771243136530651597181988040668586240449099412301454312937065604961224359235038190145852108473520413909014198600434679037524165523422401364208450631557380207996597981309168360160658308982745545442756884931141501387954248
e = 8614531087131806536072176126608505396485998912193090420094510792595101158240453985055053653848556325011409922394711124558383619830290017950912353027270400567568622816245822324422993074690183971093882640779808546479195604743230137113293752897968332220989640710311998150108315298333817030634179487075421403617790823560886688860928133117536724977888683732478708628314857313700596522339509581915323452695136877802816003353853220986492007970183551041303875958750496892867954477510966708935358534322867404860267180294538231734184176727805289746004999969923736528783436876728104351783351879340959568183101515294393048651825
n = 19873634983456087520110552277450497529248494581902299327237268030756398057752510103012336452522030173329321726779935832106030157682672262548076895370443461558851584951681093787821035488952691034250115440441807557595256984719995983158595843451037546929918777883675020571945533922321514120075488490479009468943286990002735169371404973284096869826357659027627815888558391520276866122370551115223282637855894202170474955274129276356625364663165723431215981184996513023372433862053624792195361271141451880123090158644095287045862204954829998614717677163841391272754122687961264723993880239407106030370047794145123292991433
d=wienerAttack(e,n)
print("d=",d)
m = pow(c,d,n)
print("flag = ",long_to_bytes(m))
Affine
枚举key[0] key[1] 暴力求解
babyaes
脚本(修改一下即可):
点击查看代码
from Crypto.Cipher import AES
import os
import gmpy2
from Crypto.Util.number import *
def main():
encryped_flag = b'\x8c-\xcd\xde\xa7\xe9\x7f.b\x8aKs\xf1\xba\xc75\xc4d\x13\x07\xac\xa4&\xd6\x91\xfe\xf3\x14\x10|\xf8p'
xor = 91144196586662942563895769614300232343026691029427747065707381728622849079757
xor_2 = long_to_bytes(xor)
key = xor_2[:16]*2
iv = bytes_to_long(key[16:])^bytes_to_long(xor_2[16:])
iv = long_to_bytes(iv)
aes = AES.new(key,AES.MODE_CBC,iv)
flag = aes.decrypt(encryped_flag)
print(flag)
pass
if __name__ == '__main__':
main()
Week2
滴啤
典型的dp泄露
原理
exp:
from Crypto.Util.number import *
import primefac
import gmpy2
def modinv(a,n):
return primefac.modinv(a,n) % n
e = 65537
n = 93172788492926438327710592564562854206438712390394636149385608321800134934361353794206624031396988124455847768883785503795521389178814791213054124361007887496351504099772757164211666778414800698976335767027868761735533195880182982358937211282541379697714874313863354097646233575265223978310932841461535936931
dp = 307467153394842898333761625034462907680907310539113349710634557900919735848784017007186630645110812431448648273172817619775466967145608769260573615221635
c = 52777705692327501332528487168340175436832109866218597778822262268417075157567880409483079452903528883040715097136293765188858187142103081639134055997552543213589467751037524482578093572244313928030341356359989531451789166815462417484822009937089058352982739611755717666799278271494933382716633553199739292089
for x in range(1,e):
dpe1 = dp*e-1
if dpe1%x == 0:
if(primefac.isprime((dpe1//x)+1)):
p = dpe1//x + 1
q = n//p
phi = (p-1)*(q-1)
d = modinv(e,phi)
m = pow(c,d,n)
print(m)
print(long_to_bytes(m))
不止一个pi
题目代码
from flag import flag
from Crypto.Util.number import *
import gmpy2
p = getPrime(1024)
q = getPrime(1024)
n = p**3*q**2
print("q = ",q)
print("p = ",p)
m = bytes_to_long(flag.encode())
c = pow(m,65537,n)
print("c = ",c)
这里只是将phi由(p-1)x(q-1)换成了(p ^ 3 - p ^ 2)x(q ^ 2 - q)罢了
exp:
import primefac
from Crypto.Util.number import *
import gmpy2
q = 115478867870347527660680329271012852043845868401928361076102779938370270670897498759391844282137149013845956612257534640259997979275610235395706473965973203544920469416283181677660262509481282536465796731401967694683575843183509430017972506752901270887444490905891490955975762524187534052478173966117471143713
p = 171790960371317244087615913047696670778115765201883835525456016207966048658582417842936925149582378305610304505530997833147251832289276125084339614808085356814202236463900384335878760177630501950384919794386619363394169016560485152083893183420911295712446925318391793822371390439655160077212739260871923935217
c = 4459183928324369762397671605317600157512712503694330767938490496225669985050002776253470841193156951087663107866714426230222002399666306287642591077990897883174134404896800482234781531592939043551832049756571987010173667074168282355520711905659013076509353523088583347373358980842707686611157050425584598825151399870268083867269912139634929397957514376826145870752116583185351576051776627208882377413433140577461314504762388617595282085102271510792305560608934353515552201553674287954987323321512852114353266359364282603487098916608302944694600227628787791876600901537888110093703612414836676571562487005330299996908873589228072982641114844761980143047920770114535924959765518365614709272297666231481655857243004072049094078525569460293381479558148506346966064906164209362147313371962567040047084516510135054571080612077333228195608109065475260832580192321853906138811139036658485688320161530131239854003996457871663456850196483520239675981391047452381998620386899101820782421605287708727667663038905378115235163773867508258208867367314108701855709002634592329976912239956212490788262396106230191754680813790425433763427315230330459349320412354189010684525105318610102936715203529222491642807382215023468936755584632849348996666528981269240867612068382243822300418856599418223875522408986596925018975565057696218423036459144392625166761522424721268971676010427096379610266649911939139451989246194525553533699831110568146220347603627745407449761792135898110139743498767543521297525802809254842518002190381508964357001211353997061417710783337
n = p**3*q**2
e = 65537
phi = (p**3-p**2)*(q**2-q)
d = primefac.modinv(e,phi)
m = pow(c,d,n)
print(long_to_bytes(m))
halfcandecode
题目代码:
from Crypto.Util.number import *
import gmpy2
from flag import flag
import os
from hashlib import md5
def gen_prime(number):
p = getPrime(number // 2)
q = gmpy2.next_prime(p)
return p * q
def md5_hash(m):
return md5(m.encode()).hexdigest()
e = 65537
n = gen_prime(1024)
m1 = bytes_to_long(flag[:len(flag) // 2].encode() + os.urandom(8))
c1 = pow(m1, e, n)
m2 = flag[len(flag) // 2:]
with open("out.txt","w") as f:
f.write(str(n) + '\n')
f.write(str(c1) + '\n')
for t in m2:
f.write(str(md5_hash(t))+'\n')
md5的部分可以用在线网站也可以直接枚举a~z A~Z 0~9 _来算
前面的还是一个基础的RSA 最后添加的8bit随机数没有多大影响 这里就不给exp了
Rotate Xor
题目代码:
from secret import flag
from os import urandom
from pwn import xor
from Cryptodome.Util.number import *
k1 = getPrime(64)
k2 = getPrime(64)
ROUND = 12
ciphertext = xor(flag, long_to_bytes(k1))
def round_rotate_left(num, step):
return ((num) << step | num >> (64-step)) & 0xffffffffffffffff
def encrypt_key(key):
for _ in range(ROUND):
key = round_rotate_left(key, 3) ^ k2
return key
print('ciphertext =', ciphertext)
print('enc_k1 =', encrypt_key(k1))
print('k2 =', k2)
# ciphertext = b'\x8dSyy\xd2\xce\xe2\xd2\x98\x0fth\x9a\xc6\x8e\xbc\xde`zl\xc0\x85\xe0\xe4\xdfQlc'
# enc_k1 = 7318833940520128665
# k2 = 9982833494309156947
这是一个简单的类似lfsr的循环补位 直接逆着rotate_right即可
exp:
from pwn import xor
from Crypto.Util.number import *
ciphertext = b'\x8dSyy\xd2\xce\xe2\xd2\x98\x0fth\x9a\xc6\x8e\xbc\xde`zl\xc0\x85\xe0\xe4\xdfQlc'
enc_k1 = 7318833940520128665
k2 = 9982833494309156947
def round_rotate_right(num, step):
return ((num) >> step | num << (64-step)) & 0xffffffffffffffff
for _ in range(12):
enc_k1 ^= k2
enc_k1 = round_rotate_right(enc_k1,3)
print(xor(long_to_bytes(enc_k1),ciphertext))
# flag{z3_s0lv3r_15_bri11i4nt}
broadcast
低加密指数广播攻击
这里更新一下以前的CRT脚本(这题好像要用十几组才行)
首先 手动nc 获取20组n,c
CRT求出m^e mod(N1N2N3...)后开e次方即可
exp:
def CRT(mi, ai):
M = reduce(lambda x, y: x * y, mi)
ai_ti_Mi = [a * (M // m) * gmpy2.invert(M // m, m) for (m, a) in zip(mi, ai)]
return reduce(lambda x, y: x + y, ai_ti_Mi) % M
e = 17
n=[n0,n1,n2,n3,n4,n5,n6,n7,n8,n9,n10,n11,n12,n13,n14,n15,n16,n17,n18,n19]
c=[c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13,c14,c15,c16,c17,c18,c19]
m_e = CRT(n,c)
print(m_e)
m = gmpy2.iroot(m_e,e)[0]
print(m)
print(long_to_bytes(m))
最后flag:
partial decrypt
题目代码:
from secret import flag
from Crypto.Util.number import *
m = bytes_to_long(flag)
e = 65537
p = getPrime(512)
q = getPrime(512)
n = p*q
c = pow(m,e,n)
dp = inverse(e, (p-1))
dq = inverse(e, (q-1))
m1 = pow(c,dp, p)
m2 = pow(c,dq, q)
q_inv = inverse(q, p)
h = (q_inv*(m1-m2)) % p
print('m2 =', m2)
print('h =', h)
print('q =', q)
# m2 = 4816725107096625408335954912986735584642230604517017890897348901815741632668751378729851753037917164989698483856004115922538576470127778342121497852554884
# h = 4180720137090447835816240697100630525624574275
# q = 7325294399829061614283539157853382831627804571792179477843187097003503398904074108324900986946175657737035770512213530293277111992799331251231223710406931
推一推式子
得到 c^d ≡ q*h+m2(mod p)
稍微枚举一下p(...根本不用枚举)
exp:
from Crypto.Util.number import *
m2 = 4816725107096625408335954912986735584642230604517017890897348901815741632668751378729851753037917164989698483856004115922538576470127778342121497852554884
h = 4180720137090447835816240697100630525624574275
q = 7325294399829061614283539157853382831627804571792179477843187097003503398904074108324900986946175657737035770512213530293277111992799331251231223710406931
# print(len(bin(q*h+m2)))
print(long_to_bytes(q*h+m2))
Week3
Rabin's RSA
题目
from Crypto.Util.number import *
from secret import flag
p = getPrime(64)
q = getPrime(64)
assert p % 4 == 3
assert q % 4 == 3
n = p * q
e = 2
m = bytes_to_long(flag)
c = pow(m,e,n)
print('n =', n)
print('c =', c)
# n = 201354090531918389422241515534761536573
# c = 20442989381348880630046435751193745753
由于e=2直接开根即可 注意要开all_roots
exp:
from Crypto.Util.number import *
from gmpy2 import *
from sympy import *
from primefac import *
e = 2
n = 201354090531918389422241515534761536573
p = 13934102561950901579
q = n // p
c =20442989381348880630046435751193745753
ms = nthroot_mod(c,e,n,all_roots=True)
for m in ms:
print(long_to_bytes(m))
小明的密码题
明文高位泄露攻击 cooperSmith
这里可以用sage中自带的small_roots解
在这之前还要解决一个问题 题目给的高位是一个b''我们自己写一个看看byte_to_long怎么转的
from sympy import *
from gmpy2 import *
from Crypto.Util.number import *
m = b'sm4ll_r00ts_is_brilliant#'
print(bin(bytes_to_long(m)))
m = b'sm4ll_r00ts_is_brilliant#abcdef11'
print(bin(bytes_to_long(m)))
发现不同的恰好是末64位
exp:
N = 131889193322687215946601811511407251196213571687093913054335139712633125177496800529685285401802802683116451016274353008428347997732857844896393358010946452397522017632024075459908859131965234835870443110233375074265933004741459359128684375786221535003839961829770182916778717973782408036072622166388614214899
e = 5
c = 11188201757361363141578235564807411583085091933389381887827791551369738717117549969067660372214366275040055647621817803877495473068767571465521881010707873686036336475554105314475193676388608812872218943728455841652208711802376453034141883236142677345880594246879967378770573385522326039206400578260353074379
m = 0b1110011011011010011010001101100011011000101111101110010001100000011000001110100011100110101111101101001011100110101111101100010011100100110100101101100011011000110100101100001011011100111010000100011
m = (m<<64)
ZmodN = Zmod(N)
P.<x> = PolynomialRing(ZmodN)
f = (m + x)^e - c
x0 = f.small_roots(X=2^64, beta=1)[0] # 这里的X选取不像上文用的是临界值,而是选了一个我们未知的x的最大可能值。X的选取并非严格,但至少得保证比临界值小。
print("m:", m + x0)
sage秒出m
最后long_to_byte即可
knapsack
背包加密
学习
这里了解原理后用Git上的脚本修改一下即可
sage跑出
这里直接unhexfi的话由于位数是奇数 所以要枚举最后一位的情况
'''
255 [1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0] --- 666c61677b4c6174746963655f726564756374696f6e2363333636323534317
'''
import binascii
from Crypto.Util.number import *
flag = '666c61677b4c6174746963655f726564756374696f6e2363333636323534317'
lst = '0123456789abcdef'
# flag = '415349535f3962643364356664323432323638326331393536383830366130373036316365'
# 415349535f3962643364356664323432323638326331393536383830366130373036316365
# 415349535f3962643364356664323432323638326331393536383830366130373036316365
for c in lst:
fflag = flag + c
print(binascii.unhexlify(fflag))
# print(long_to_bytes(flag))
babyrandom
推推式子
exp:
from Crypto.Util.number import *
from gmpy2 import *
from sympy import *
from primefac import *
x1 = 12237514397472333652372078471141394089398703096615619384528520579893044503154
x2 = 37432408689751793777365062467818023081896697763737797195412253183472118989474
x3 = 33863903225262985844958383123415913586438827627942393693805450163840109911629
p = 64999433139797068147576269731948390094958654326970231465808792590598519729077
inv_x1 = modinv(x1,p)
inv_x2 = modinv(x2,p)
inv_x3 = modinv(x3,p)
xx = (x2*inv_x1-x3*inv_x2)%p
yy = (inv_x1-inv_x2)%p
b = (xx*modinv(yy,p))%p
print(b)
a = ((x2-b)*inv_x1)%p
print(a)
# b = 49669923087224127429737140938959417171295400860353416579940773763365163492628
# a = 64999433139797068147576269731948390094958654326970231465808792590598519729076
inv_a = modinv(a,p)
x = ((x1-b)*inv_a)%p
print(long_to_bytes(x))
ez_crt
这。。。有文献研究过链接
这个算法的原理找半天也找不着 就当结论记着吧
(也就是说后面给的一大堆全是无效信息。。。)
solution.py
p = GCD(pow(S_, e, n) - m, n)
q = n // p
...
Door
CBC翻转攻击
chall.py
from secret import flag
import string
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
from os import urandom
import re
key = urandom(16)
menu = '''
[+] WatchDog Security System
[+] Copyright (c) 1010 by School of Natural Philosophy
please select your option:
1. Unlock Secret Entry
2. Help
3. Exit
'''
valid_code = [1033,3329,4431,5052]
auth_context_pattern = re.compile(r'^SoNP#[0-9]{4}$')
def auth_context_checker(ctx : bytes):
for c in ctx:
if chr(c) not in string.printable:
return False
if auth_context_pattern.match(ctx.decode()) : return True
return False
def unlock():
token = bytes.fromhex(input('Enter your token > '))
auth_code = bytes.fromhex(input('Enter your authentication code > '))
cipher = AES.new(key, AES.MODE_CBC,token)
check = cipher.decrypt(auth_code)
try:
msg = unpad(check, 16)
if auth_context_checker(msg) and int(msg[5:].decode()) in valid_code:
print('door unlocked, here is your reward')
print(flag)
else:
print('get out')
except Exception as e:
print('oops, something wrong')
print(e)
def help():
print('To unlock the door, please enter your token and authentication code.')
while True:
print(menu)
opt = input('> ')
try:
opt = int(opt)
if opt == 1:
unlock()
elif opt == 2:
help()
elif opt == 3:
break
else:
print('invalid option')
except:
print('oh no, something wrong!')
我们要想办法控制iv使得decrypt后得到我们想要的数据
服务端会把密文解密之后的填充状态返回, 那么我们只要控制iv, 使得解密之后的明文产生"...\x01", "...\x02\x02" ...的状态,获得明文为"\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10"对应的IV, 然后利用xor把我们想要输入的内容合并到这个IV里面。
solution.py
from pwn import *
from Crypto.Cipher import *
from Crypto.Util.Padding import *
from os import urandom
from tqdm import tqdm
r = remote('node4.buuoj.cn',28224)
auth_code = urandom(16)
token = urandom(16)
diff = [0]*16
for i in reversed(range(16)):
for b in (range(256)):
diff[i] = b
tmp_tk = xor(token,bytes(diff))
r.sendlineafter(b'> ',b'1')
r.sendlineafter(b'> ',tmp_tk.hex().encode())
r.sendlineafter(b'> ',auth_code.hex().encode())
res = r.recvline()
if b'out' in res:
if i!=0:
for j in range(i,16):
diff[j] = diff[j] ^ (16-i) ^ (16-i+1)
break
forged_token = xor(token,bytes(diff))
forged_token = xor(forged_token,b'\x10'*16)
forged_token = xor(forged_token,pad(b'SoNP#3329',16))
r.sendlineafter(b'> ',b'1')
r.sendlineafter(b'> ', forged_token.hex().encode())
r.sendlineafter(b'> ', auth_code.hex().encode())
r.interactive()
Week5
School of CRC32
chall.py
import secrets
from secret import flag
import zlib
ROUND = 100
LENGTH = 20
print('Extreme hard CRC32 challenge')
print('ARE YOU READY')
for i in range(ROUND):
print('ROUND', i, '!'*int(i/75 + 1))
target = secrets.randbits(32)
print('Here is my CRC32 value: ', hex(target))
dat = input('Show me some data > ')
raw = bytes.fromhex(dat)
if zlib.crc32(raw) == target and len(raw) == LENGTH:
print("GREAT")
else:
print("OH NO")
exit()
print("Congratulation! Here is your flag")
print(flag)
这里直接运用crcsolver求解
有几个注意点 :
- 对题目所给target的数据提取
- crcsolver得到后要填充为40位hex (这样转成byte才是20位)
solution.py
from pwn import *
import secrets
import zlib
import crcsolver
from libnum import *
p = remote("node4.buuoj.cn",29670)
ROUND = 100
LENGTH = 20
for i in range(ROUND):
p.recvuntil('Here is my CRC32 value: ')
target = (p.recvline())
# print(target)
target = eval(target)
m = crcsolver.solve(b'_'*LENGTH, range(8*20), target, zlib.crc32)
# print(hex(s2n(m))[2:])
# print(len(bytes.fromhex(hex(s2n(m))[2:])))
msg = hex(s2n(m))[2:].zfill(40)
p.sendlineafter('data >',msg)
p.interactive()
last_signin
chall.py
from Crypto.Util.number import *
flag = b'?'
e = 65537
p, q = getPrime(1024), getPrime(1024)
N = p * q
gift = p&(2**923-2**101)
m = bytes_to_long(flag)
c = pow(m, e, N)
print("N = ",N)
print("gift = ",gift)
print("c = ",c)
"""
N = 12055968471523053394851394038007091122809367392467691213651520944038861796011063965460456285088011754895260428814358599592032865236006733879843493164411907032292051539754520574395252298997379020268868972160297893871261713263196092380416876697472160104980015554834798949155917292189278888914003846758687215559958506116359394743135211950575060201887025032694825084104792059271584351889134811543088404952977137809673880602946974798597506721906751835019855063462460686036567578835477249909061675845157443679947730585880392110482301750827802213877643649659069945187353987713717145709188790427572582689339643628659515017749
p0 = 70561167908564543355630347620333350122607189772353278860674786406663564556557177660954135010748189302104288155939269204559421198595262277064601483770331017282701354382190472661583444774920297367889959312517009682740631673940840597651219956142053575328811350770919852725338374144
c = 2475592349689790551418951263467994503430959303317734266333382586608208775837696436139830443942890900333873206031844146782184712381952753718848109663188245101226538043101790881285270927795075893680615586053680077455901334861085349972222680322067952811365366282026756737185263105621695146050695385626656638309577087933457566501579308954739543321367741463532413790712419879733217017821099916866490928476372772542254929459218259301608413811969763001504245717637231198848196348656878611788843380115493744125520080930068318479606464623896240289381601711908759450672519228864487153103141218567551083147171385920693325876018
"""
以前p的高位泄露都是告诉了高位或低位 而这题给的是中间位
参考 https://www.anquanke.com/post/id/193939#h3-28
solution.py
N = 12055968471523053394851394038007091122809367392467691213651520944038861796011063965460456285088011754895260428814358599592032865236006733879843493164411907032292051539754520574395252298997379020268868972160297893871261713263196092380416876697472160104980015554834798949155917292189278888914003846758687215559958506116359394743135211950575060201887025032694825084104792059271584351889134811543088404952977137809673880602946974798597506721906751835019855063462460686036567578835477249909061675845157443679947730585880392110482301750827802213877643649659069945187353987713717145709188790427572582689339643628659515017749
p0 = 70561167908564543355630347620333350122607189772353278860674786406663564556557177660954135010748189302104288155939269204559421198595262277064601483770331017282701354382190472661583444774920297367889959312517009682740631673940840597651219956142053575328811350770919852725338374144
c = 2475592349689790551418951263467994503430959303317734266333382586608208775837696436139830443942890900333873206031844146782184712381952753718848109663188245101226538043101790881285270927795075893680615586053680077455901334861085349972222680322067952811365366282026756737185263105621695146050695385626656638309577087933457566501579308954739543321367741463532413790712419879733217017821099916866490928476372772542254929459218259301608413811969763001504245717637231198848196348656878611788843380115493744125520080930068318479606464623896240289381601711908759450672519228864487153103141218567551083147171385920693325876018
PR = PolynomialRing(Zmod(N), names='x,y')
x, y = PR.gens()
def bivariate(pol, XX, YY, kk=4):
N = pol.parent().characteristic()
f = pol.change_ring(ZZ)
PR, (x, y) = f.parent().objgens()
idx = [(k - i, i) for k in range(kk + 1) for i in range(k + 1)]
monomials = list(map(lambda t: PR(x ** t[0] * y ** t[1]), idx))
# collect the shift-polynomials
g = []
for h, i in idx:
if h == 0:
g.append(y ** h * x ** i * N)
else:
g.append(y ** (h - 1) * x ** i * f)
# construct lattice basis
M = Matrix(ZZ, len(g))
for row in range(M.nrows()):
for col in range(M.ncols()):
h, i = idx[col]
M[row, col] = g[row][h, i] * XX ** h * YY ** i
# LLL
B = M.LLL()
PX = PolynomialRing(ZZ, 'xs')
xs = PX.gen()
PY = PolynomialRing(ZZ, 'ys')
ys = PY.gen()
# Transform LLL-reduced vectors to polynomials
H = [(i, PR(0)) for i in range(B.nrows())]
H = dict(H)
for i in range(B.nrows()):
for j in range(B.ncols()):
H[i] += PR((monomials[j] * B[i, j]) / monomials[j](XX, YY))
# Find the root
poly1 = H[0].resultant(H[1], y).subs(x=xs)
poly2 = H[0].resultant(H[2], y).subs(x=xs)
poly = gcd(poly1, poly2)
x_root = poly.roots()[0][0]
poly1 = H[0].resultant(H[1], x).subs(y=ys)
poly2 = H[0].resultant(H[2], x).subs(y=ys)
poly = gcd(poly1, poly2)
y_root = poly.roots()[0][0]
return x_root, y_root
pol = 2 ** 923 * x + y + p0
x, y = bivariate(pol, 2 ** 101, 2 ** 101)
p = 2 ** 923 * x + y + p0
q = N // p
print(p,q,sep=' , ')
# from Crypto.Util.number import *
# from primefac import *
# p,q = 128316995030969915324601380638393686940451314028029847288048482890311391444850912731036515693294185876094548175445535907681477441597112946116144447110741965169166242532652418536974280062421433117597771884350348782061336417186073214602745554392782563801452571827824278044551188124531752043347553290530270395447 , 93954572959047928343011750832384121004425708514797352779274995744988621009506935222019019171047965401245311260375453924225343494879356560534244565490966730992944825873075214193169703861204568164588812686254102717072093288624081316906954278209584119401170082334613277995260895181460040974631476760070669352467
# e = 65537
# d = modinv(e,(p-1)*(q-1))
# print(long_to_bytes(pow(c,d,N)))