from sage.modules.free_module_integer import IntegerLattice from random import randint import sys from itertools import starmap from operator import mul
# Babai's Nearest Plane algorithm # from: http://mslc.ctf.su/wp/plaidctf-2016-sexec-crypto-300/ defBabai_closest_vector(M, G, target): small = target for _ inrange(1): for i inreversed(range(M.nrows())): c = ((small * G[i]) / (G[i] * G[i])).round() small -= M[i] * c return target - small Z = GF(p) m = 30 n = 1
A = matrix(ZZ, m + n, m) for i inrange(m): A[i, i] = p for x inrange(m): for y inrange(n): A[m + y, x] = ts[x] print("开始LLL算法") lattice = IntegerLattice(A, lll_reduce=True) print("LLL done") gram = lattice.reduced_basis.gram_schmidt()[0] target = vector(ZZ, gs) res = Babai_closest_vector(lattice.reduced_basis, gram, target) print("Closest Vector: {}".format(res)) key = res[0]*inverse(ts[0],p) % p key_bytes = str(key).encode()[:16] cipher = AES.new(key_bytes, AES.MODE_CBC, iv) flag = unpad(cipher.decrypt(ciphertext), 16).decode() print(f"Flag: {flag}")
# 预计算阶段:存储 x_r = ck * r^(-e) mod n xr_dict = {} for r in range(1, T + 1): # 计算 r^e mod n r_e = pow(r, e, n) # 计算逆元,若逆元不存在则检查是否分解n try: inv_r_e = inverse(r_e, n) except ValueError: g = GCD(r_e, n) if g != 1: p = g q = n // g d = inverse(e, (p-1)*(q-1)) key = pow(ck, d, n) print(f"[!] Factor found: KEY = {key}") exit() continue xr = (ck * inv_r_e) % n if xr not in xr_dict: xr_dict[xr] = r
print("[*] Precomputation completed. Searching for s...")
# 搜索阶段:计算 s^e mod n,寻找匹配的x_r for s in range(1, T + 1): s_e = pow(s, e, n) if s_e in xr_dict: r = xr_dict[s_e] key_candidate = r * s # 验证KEY是否满足条件 if pow(key_candidate, e, n) == ck: print(f"[+] KEY found: {key_candidate}") # 生成flag key_hash = md5(str(key_candidate).encode()).hexdigest() flag = f"NSSCTF{{{key_hash}}}" print(f"[+] Flag: {flag}") exit()
def continuedfraction(a,b,n): quotationlist =[a//b,b//(a%b)] r_list=[a%b,b%(a%b)] i = 1 while r_list[i] != 0: quotationlist.append(r_list[i-1]//r_list[i]) r_list.append(r_list[i-1]%r_list[i]) i += 1 d_list = [1,quotationlist[1]] k_list = [quotationlist[0],quotationlist[0]*quotationlist[1]+1] for j in range(2,len(quotationlist)): d_list.append(quotationlist[j]*d_list[j-1]+d_list[j-2]) #代入上面递推公式# k_list.append(quotationlist[j]*k_list[j-1]+k_list[j-2]) for s in range(len(d_list)): if(k_list[s]/d_list[s] == n and (d_list[s]*e -1)% k_list[s] == 0): #判断是否正确,即k整除de-1# print(d_list[s]) continuedfraction(e,N,e/N)[0] d = 1051176891915773585468122074232642482031663118639646043742447 ink = pow(c,d,N) print(ink)
后面就是DSA问题了
两次DSA,只要k不同,第一次是k,第二次是k+ink
所以 简简单单解个二元一次方程组得到
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
from hashlib import * from Crypto.Util.number import * from Crypto.Util.Padding import unpad from Crypto.Cipher import AES msg = "GHCTF-2025".encode() ink = 888451 h = int(sha256(msg).digest().hex(),16) r1,s1= (105538622724986198173818280402723234123231812870, 165871242333491991006684781121637801537623792920) r2,s2= (895673018852361693797535983771888430717799939767, 511956887428148277909616673338517730698888202223) q= 974306102330898613562307019447798934376234044213 x = (s1*s2*ink+(s2-s1)*h)*inverse(s1*r2-s2*r1,q)% q key = sha1(str(x).encode()).digest()[:16] ciphertext = b'\xb0\ra\x9c\xeb9y\xd5k\xfde\xdfJ\xba\n\xce^u\xae\x81J8\xe4\x8da\xdf;H@WV5' cipher = AES.new(key, AES.MODE_ECB) flag = cipher.decrypt(ciphertext) flag = unpad(flag,16) print(flag.decode())
f1 = P(str(f1)) f2 = x*y -n syl_x = f1.sylvester_matrix(f2,x) r = syl_x.determinant() r1 = r.univariate_polynomial().monic() kq = w - pow(2,r1(1),n) q = GCD(kq,n) p = n // q print(p,q)
这里p,q需要分类讨论
注意到题目说
1
assertall(chr(i) in ''.join(list(set(str(p)))) for i in flag[7:-1:])