题目描述:
chal_sage部分:
from Crypto.Util.number import *
from random import *
from secrets import flag
def gen_random(seed, P, Q, r_list, times):
s = seed
for i in range(times):
s = int((s * P)[0])
r = int((s * Q)[0])
r_list.append(r)
return r_list
def gen_seed():
seed = getRandomNBitInteger(32)
return seed
def getP_Q():
Q = Curve.random_point()
P = 114514*Q
return P, Q
def enc(flag, rlist):
seq = list(randint(0, 1) for _ in range(4))
add = rlist[55]*(seq[0]*rlist[66] + seq[1]*rlist[77] + seq[2]*rlist[88] + seq[3]*rlist[99])
xor = pow(rlist[114], rlist[514], rlist[233]*rlist[223])
enc = (bytes_to_long(flag)^^xor)+add
return enc
nums = 600
seed = gen_seed()
p = 58836547289031152641641668761108233140346455328711205590162376160181002854061
F = GF(p)
a = F(114)
b = F(514)
Curve = EllipticCurve(F, [a, b])
P, Q = getP_Q()
r_list = []
r_list = gen_random(seed, P, Q, r_list, nums)
ENCFLAG = enc(flag, r_list)
print(ENCFLAG)
print(P, Q)
print(r_list[0])
'''
4911741083112145038719536311222612998219730565328651097326896414315857050336523018712625917027324116103593300559128797807261543857571883314990480072241188
#####################################
#####################################
Oh no, P, Q and r_list[0] are accidentally lost, but John seems to know, you can ask him about these missing values ::>_<::
'''
homework部分:
from Crypto.Util.number import *
from params import N, E, D
from leak_data import P, Q, r_1
import re
def challenge():
meum = '''option:
1: get pubkey
2: get sign
3: verify
4: exit'''
print("Hi, I am John. If you help me with my homework, I'll give you the data that I know ( ̄o ̄) . z Z")
print(meum)
sign = None
while True:
print('[+]input your option: ', end='')
your_input = input()
if your_input == '1':
print(f'[+]N = {N}')
print(f'[+]e = {E}')
continue
elif your_input == '2':
sign = pow(bytes_to_long(MSG.encode()), D, N)
print(f'[+]sign = {sign}')
continue
elif your_input == '3':
if sign is None:
print('[+]Please input option 2 to generate sign first.')
continue
msg_user = input("[+]Please input your message: ")
n = int(input("[+]Please input n: "))
e = int(input("[+]Please input e: "))
if e <= 3:
print('[+]e is invalid')
break
else:
if re.match(r'I can not agree more!!!$', msg_user):
if pow(bytes_to_long(msg_user.encode()), e, n) == sign:
print("Goooooooood! You are my hero! I can give you the data that I know ╰(*°▽°*)╯")
print(f'Leak_data: \n P={P}\n Q={Q}\n first num in r_list={r_1}')
break
else:
print('[+]Error signature!')
break
else:
print('[+]Error message!')
break
elif your_input == '4':
break
if __name__ == '__main__':
MSG = 'This is an easy challenge'
challenge()
题目分析:
import gmpy2
from Crypto.Util.number import *
N = 7399403457188876147280737704413998161465702407270784053949887695340528233758555062010898995255039810187699911928866167640259018538192441232641067730711771
E = 65537
sign = 1320070156891033288626051716868212806309097835600533098946778415708131349531482538706467629025443890643255446066240480813053241479563851572261696377893792
MSG = 'This is an easy challenge'
msg_user = 'I can not agree more!!!'
# pow(MSG,D,N) = pow(msg_user,e,n) = sign,要求e,n
# 题目中限制条件e > 3,那我就令e = 4或5喽,或者构造光滑数
-
pow(MSG,D,N) = pow(msg,e,n) = sign,求e,n
题目中限制条件e > 3,那我直接令e = 4或5咯,或者构造光滑数
-
法一(构造光滑数):
from Crypto.Util.number import * def gen_primes(nbit, imbalance): """ :param nbit: 最终光滑数比特数 :param imbalance: 最小单位比特数 :return: 比特数 """ p = int(2) FACTORS = [p] while p.bit_length() < nbit - 2 * imbalance: factor = getPrime(imbalance) FACTORS.append(factor) p *= factor rbit = (nbit - p.bit_length()) // 2 while True: r, s = [getPrime(rbit) for _ in '01'] _p = p * r * s if _p.bit_length() < nbit: rbit += 1 if _p.bit_length() > nbit: rbit -= 1 if isPrime(_p + 1): FACTORS.extend((r, s)) p = _p + 1 break FACTORS.sort() return (p, FACTORS) MSG = 'This is an easy challenge' msg = 'I can not agree more!!!' sign = 1320070156891033288626051716868212806309097835600533098946778415708131349531482538706467629025443890643255446066240480813053241479563851572261696377893792 M = bytes_to_long(MSG.encode()) m = bytes_to_long(msg.encode()) n, n_fac = gen_primes(512, 20) # n = 4042948769941627341019324611789396195045815639020219860408774627904312552947443280269093998428541432391837271401229040233775660233089444891431013462995967
-
离散对数sage求解(模数小 / 阶光滑)
# h = g^x mod p # c1 = m^e mod n1 p = n g = m h = sign x = discrete_log(Mod(h,p),Mod(g,p)) print(pow(m,x,p)==sign) print('n =', p) print('e =', x)
-
也可以直接:
n = 4042948769941627341019324611789396195045815639020219860408774627904312552947443280269093998428541432391837271401229040233775660233089444891431013462995967 G = Zmod(n) m1 = G(m) c1 = G(sign) print(ZZ(discrete_log(c1,m1)))
-
这部分好像好像好像啊!discrete_log:
a=2275123956203765363233765961297507379124236980967603145079239177208264523438555378298177602517599708533004805369986246098127863480798528206818576888655427591685534478161571717613561380234338516607855593046949 fac = [2, 136327, 169937, 313351, 321427, 323377,356887, 413783, 519733,792413, 860077, 906289, 976501] G=Zmod(N) m1=G(m) c1=G(a) oo=[] for i in fac: h=(N-1)//i dlp1=discrete_log(c1**h,m1**h) oo.append(int(dlp1)) sk=crt(oo,fac) mod = prod(fac) for i in range(100): print(long_to_bytes(int(sk + i * mod))) # 或: m = 1391372358062724416224243990838035874507346098208831800403257 a=2275123956203765363233765961297507379124236980967603145079239177208264523438555378298177602517599708533004805369986246098127863480798528206818576888655427591685534478161571717613561380234338516607855593046949 G=Zmod(N) m1=G(m) c1=G(a) print(long_to_bytes(ZZ(discrete_log(c1,m1)))) # Neepu{Nsmoothnumber}
-
方法二:
MSG = 'This is an easy challenge' msg = 'I can not agree more!!!' sign = 1320070156891033288626051716868212806309097835600533098946778415708131349531482538706467629025443890643255446066240480813053241479563851572261696377893792 e = 4 n = bytes_to_long(msg.encode())**e - sign print('e = ',e) print('n = ',n)
-
接下来求后面部分:
s1 = int((s0 * P)[0]) r1 = int((s1 * Q)[0]) P = 114514 * Q s1 = (seed * P).x, r1 = (s1 * Q).x = rlist[0] s2 = (s1 * P).x ===> s2 = (s1 * 114514 * Q).x = (114514 * s1 * Q).x = (114514*Curve.lift_x(r0))[0] (PS:Curve.lift_x() 方法会在给定的 x 坐标上搜索相应的 y 值,以获得椭圆曲线上的曲线点。 结果返回的是一个曲线点对象,包含了曲线上的 x 和 y 坐标)
# sage from Crypto.Util.number import * nums = 600 p = 58836547289031152641641668761108233140346455328711205590162376160181002854061 F = GF(p) a = F(114) b = F(514) E = EllipticCurve(F,[a, b]) P=E(24181776889473219401017476947331354458592459788552219617833554538756564211844, 33783050059316681746742286692492975385672807657476634456871855157562656976035) Q=E(16104852983623236554878602983757606922134442855643833150623643268638509292839, 3562830444362909774600777083869972812060967068803593091854731534842281574275) r0 = 50920555924101118476219158701093345090627150442059647242030060086626996278598 rlist = [r0] for _ in range(600): s = (E.lift_x(rlist[-1]) * 114514)[0] rlist.append((int(s) * Q)[0]) r_list = [r0] for i in range(515): R0 = E.lift_x(r_list[-1]) s1 = ZZ((114514 * R0)[0]) r1 = ZZ((s1*Q)[0]) r_list.append(r1) rlist = [int(i) for i in rlist] # 不可少 ''' 没加这行rlist中数据类型<class 'sage.rings.integer.Integer'> 加了这行rlist中数据类型<class 'int'> 在Sage中,Integer是一个类,而int是Python的内置数据类型。与Java类似,在使用Sage中的Integer时,需要通过调用其方法或属性将其转换为Python的int类型才能进行数值计算或比较等操作。虽然Sage中的Integer与Python的int都可以表示整数,但它们的底层实现略有不同 ''' for i in range(2 ^ 4): seq = [(i >> 3) & 1, (i >> 2) & 1, (i >> 1) & 1, i & 1] add = rlist[55]*(seq[0]*rlist[66] + seq[1]*rlist[77] + seq[2]*rlist[88] + seq[3]*rlist[99]) xor = pow(rlist[114], rlist[514], rlist[233]*rlist[223]) flag = long_to_bytes(int((enc - add) ^^ xor)) if b'SCTF' in flag: print(flag) # b'SCTF{Th1s_i5_my_happy_s0ng_I_like_to_5ing_it_@ll_day_1ong}'
又学到了!