pading
题目:
from Crypto.Util.number import *
import gmpy2
flag = b'SHCTF{********}'
assert len(flag) == 39
p = getPrime(512)
q = getPrime(512)
n = p * q
e = 0x3
pad = b'a_easy_problem'
c = pow(bytes_to_long(flag + pad),e,n)
print(f'n = {n}')
print(f'c = {c}')
思路解析:
这里的明文换成了flag+pad,pad长度与内容我们已知,flag我们已知其长度
这里涉及到coppersmith定理攻击
(基于LLL算法),Coppersmith可以用于求多项式的小根
经常用于“已知某些二进制位,求剩余位
”的问题
而其应用之一是已知明文攻击
,就是已知部分明文,我们能求出全部明文
但其也有局限性:已知明文长度不能过短
len(flag)=39
(bytes_to_long(flag+pad)**e=[x*(2**8)*len(pad)+bytes_to_long(pad)]**3
#x指代flag
#这里不详细解释bytes_to_long()的转换原理了,可自行百度
x=(2**(8*39)
#这里x是指其上限,即最大取值上限
flag的二进制位长度:8*39=312,e次方后位936位
n的二进制长度:1024
beta(β)的取值依据:936/1024≈0.9
epsilon(ε)的值通常设定为β的1/8,即ε = β / 8
实际应用中需要不断调整beta和epsilon的值来找到满足答案的解
完整脚本:
import libnum
n = 101194231761192803646875794770841105131876105333404505987513576849142365482512109876401629071314564545841743473668262668053559550015874646299248232349238400201145583346187330958825878235324968882794481192056169683711007095999439320830763275487477094590502701333963154552470777678553556993349171608134555815527
c = 54067443511581567434123971345564905390315631873898717856316286990552318113901362505672245448553258416669456882532743580961176229271906817289588426185966004215569829572814038485471312399063659287164712291139771809733004385057875146223151700601326161190474536508680332925332614914475852998934930375151571163346
e = 0x3
pad = b'a_easy_problem'
PR.<x> = PolynomialRing(Zmod(n))
f = (x * 256 ** len(pad) + libnum.s2n(pad)) ** e - c
f = f.monic()
#转换成首一多项式,加快求解
root = f.small_roots(X=2 ** (39 * 8),beta=0.9,epsilon=0.03)
print(root)
print(libnum.n2s(int(root[0])))
#SHCTF{aRE_yOu_pADddin6_mE_6OY_3cC65T9E} //本题是动态flag
当epslion过小时,格过大,LLL算法会非常耗时,这里测试epsilon=0.01就需要的时间比较长
所以一般取0.01左右出不来,就要调整方法。
如果大家没有sage的话,可以从网盘中下载
https://pan.quark.cn/s/f74042154b3d
worde很大
这道题目我在下面连接文章已经详细解释了,想了解的师傅可自行跳转
dp泄露
魔鬼的步伐
这道题目也同样请跳转查看
p-1光滑数
E&R
题目:
#sage
from Crypto.Util.number import *
from secret import flagflag = flag[6:-1]
l = len(flag)
m1 = bytes_to_long(flag[:l//2])
m2 = bytes_to_long(flag[l//2:])
#RSA
p = getPrime(256)
q = getPrime(256)
n = p * q
e = 65537
r_q = int(bin(q)[2:][::-1] , 2)
leak = p ^^ r_q
c = pow(m2,e,n)#ECC
E = EllipticCurve(Zmod(n),[114514,1919810])
G = E.lift_x(Integer(m1))
P = G * e
print(f'leak = {leak}')
print(f'n = {n}')
print(f'c = {c}')
print(f'P = {P}')
# leak = 5599968251197363876087002284371721787318931284225671549507477934076746561842
# n = 7120275986401660066259983193598830554385933355254283093021239164350142898387660104515624591378875067038235085428170557400012848874756868985306042421950909
# c = 6803450117490196163076010186755045681029929816618361161925865477601994608941714788803007124967390157378525581080320415602012078322064392991884070073083436
# P = (4143131125485719352848137000299706175276016714942734255688381872061184989156686585992844083387698688432978380177564346382756951426943827434190895490233627 : 3879946878859691332371384275396678851932267609535096278038417524609690721322205780110680003522999409696718745532857001461869452116434787256032366267905519 : 1)
思路解析:
第一部分flag
:这里涉及到剪枝问题
这里建议参考鸡块师傅的blog:Crypto趣题-剪枝
搜索方式
从两端向中间搜索
每一次搜索,需利用当前 pxorq 两端的bit位。这是因为,pxorq 的当前最高位对应p的最高位及q的最低位,pxorq 的当前最低位对应p的最低位及q的最高位 (其中最高、最低均是对于当前搜索而言)
如果当前需搜索的最高位为”1”,则对应两种可能:
p该位为1,q对应低位为0;
p该位为0,q对应低位为1。剩下依此类推
满足条件
将p、q未搜索到的位全填0,乘积应小于n
将p、q未搜索到的位全填1,乘积应大于n
p、q 低 k 位乘积再取低 k 位,应与 n 的低 k 位相同
额!!!,以上内容纯属借鉴鸡块师傅的内容
对应的脚本如下:
from Crypto.Util.number import *
import syspxorq = 5599968251197363876087002284371721787318931284225671549507477934076746561842
n = 7120275986401660066259983193598830554385933355254283093021239164350142898387660104515624591378875067038235085428170557400012848874756868985306042421950909
c = 6803450117490196163076010186755045681029929816618361161925865477601994608941714788803007124967390157378525581080320415602012078322064392991884070073083436
e = 65537
pxorq = str(bin(pxorq)[2:]).zfill(256)def find(ph, qh, pl, ql):l = len(ph)tmp0 = ph + (256 - 2 * l) * "0" + pltmp1 = ph + (256 - 2 * l) * "1" + pltmq0 = qh + (256 - 2 * l) * "0" + qltmq1 = qh + (256 - 2 * l) * "1" + qlif (int(tmp0, 2) * int(tmq0, 2) > n):returnif (int(tmp1, 2) * int(tmq1, 2) < n):returnif (int(pl, 2) * int(ql, 2) % (2 ** (l - 1)) != n % (2 ** (l - 1))):returnif (l == 128):pp0 = int(tmp0, 2)if (n % pp0 == 0):pf = pp0qf = n // pp0print(pf)print(qf)phi = (pf - 1) * (qf - 1)d = inverse(e, phi)m1 = pow(c, d, n)print(long_to_bytes(m1))exit()else:if (pxorq[l] == "1" and pxorq[255 - l] == "1"):find(ph + "1", qh + "0", "1" + pl, "0" + ql)find(ph + "0", qh + "0", "1" + pl, "1" + ql)find(ph + "1", qh + "1", "0" + pl, "0" + ql)find(ph + "0", qh + "1", "0" + pl, "1" + ql)elif (pxorq[l] == "1" and pxorq[255 - l] == "0"):find(ph + "1", qh + "0", "0" + pl, "0" + ql)find(ph + "0", qh + "0", "0" + pl, "1" + ql)find(ph + "1", qh + "1", "1" + pl, "0" + ql)find(ph + "0", qh + "1", "1" + pl, "1" + ql)elif (pxorq[l] == "0" and pxorq[255 - l] == "1"):find(ph + "0", qh + "0", "1" + pl, "0" + ql)find(ph + "0", qh + "1", "0" + pl, "0" + ql)find(ph + "1", qh + "0", "1" + pl, "1" + ql)find(ph + "1", qh + "1", "0" + pl, "1" + ql)elif (pxorq[l] == "0" and pxorq[255 - l] == "0"):find(ph + "0", qh + "0", "0" + pl, "0" + ql)find(ph + "1", qh + "0", "0" + pl, "1" + ql)find(ph + "0", qh + "1", "1" + pl, "0" + ql)find(ph + "1", qh + "1", "1" + pl, "1" + ql)find("1", "1", "1", "1")
第二部分flag
:涉及到ecc
(椭圆曲线问题)
因为这里的模数n是一个非素数,想要求椭圆曲线的阶很难
所以将其化成求p和q的阶
E1 = EllipticCurve(Zmod(p),[114514,1919810])
E2 = EllipticCurve(Zmod(q),[114514,1919810])
phi = Ep.order()*Eq.order()
求出阶后,求e的逆元d
已知P = G * e
,两边同时乘以d,就变成了P*d=G
进而用函数xy()
求得G点的x坐标
(G = E.lift_x(Integer(m1))
这里用m1作为x坐标生成E上的一点G)
脚本如下:
from Crypto.Util.number import *p = 64760524083545528318139240449356269097871629401328435356643510319660757701117
q = 109947782034870726628911928816041880655659770652764045401662566933641952899777
e = 65537
n = 7120275986401660066259983193598830554385933355254283093021239164350142898387660104515624591378875067038235085428170557400012848874756868985306042421950909
E = EllipticCurve(Zmod(n),[114514,1919810])
E1 = EllipticCurve(Zmod(p),[114514,1919810])
E2 = EllipticCurve(Zmod(q),[114514,1919810])
P = E(4143131125485719352848137000299706175276016714942734255688381872061184989156686585992844083387698688432978380177564346382756951426943827434190895490233627,3879946878859691332371384275396678851932267609535096278038417524609690721322205780110680003522999409696718745532857001461869452116434787256032366267905519)phi = E1.order()*E2.order()
d = inverse_mod(e,phi)
G = P*d
x = G.xy()[0]
flag = long_to_bytes(int(x))
print(flag)
ezECC
题目:
from Crypto.Util.number import *
from flag import flagassert flag.startswith(b'SHCTF{')m = next_prime(bytes_to_long(flag))
p = getPrime(512)
a,b = getPrime(128),getPrime(128)
E = EllipticCurve(Zmod(p),[a,b])
k = getPrime(256)
A1 = E.random_point()
A2 = A1*k
M = E.lift_x(m)
C = M+A2print('p = ',p)
print('k = ',k)
print('A1 = ',A1)
print('C = ',C)
思路解析:
这里我们不知道a和b的值,但我们可以根据两个椭圆曲线上的点A1和C联立来求
a = inverse(A1[0]-C[0],p)*((A1[1]**2-A1[0]**3)-(C[1]**2-C[0]**3))% p
b = (C[1]**2-C[0]**3-a*C[0])%p
然后可以直接求M的x坐标
E = EllipticCurve(Zmod(p),[a,b])
A1 = E(A1)
C = E(C)
M = C-k*A1
Mx = (M.xy())[0]
因为m是flag的下一个素数,按照两个素数之间间距不大于1500
我们得到以下脚本:
for i in range(1500):m = long_to_bytes(int(Mx-i))try:print(m.decode())except:continue
完整脚本如下:
from Crypto.Util.number import *
p = 9799485259524549113003780400336995829253375211044694607315372450399356814285244762186468904824132005209991983177601498069896166228214442123763065076327679
k = 73771953838487511457389800773038323262861649769228176071578897500004883270121
A1 = (5945412329827707694132352090606154232045921322662767755331097180167148601629747751274580872108985870208681845078153424348847330421799769770041805208089791,4113102573821904570542216004200810877456931033522276527318388416329888348077285857968081007666714313806776668203284797556825595791189566621228705928598709)
C = (2336301464307188733995312208152021176388718095735565422234047912672553316288080052957448196669174030921526180747767251838308335308474037066343018337141276,6868888273736103386336636953449998615833854869329393895956720058438723636197866928342387693671211918574357564701700555086194574821628053750572619551290025)
a = inverse(A1[0]-C[0],p)*((A1[1]**2-A1[0]**3)-(C[1]**2-C[0]**3))% p
b = (C[1]**2-C[0]**3-a*C[0])%pE = EllipticCurve(Zmod(p),[a,b])
A1 = E(A1)
C = E(C)
M = C-k*A1
Mx = (M.xy())[0]
for i in range(292):m = long_to_bytes(int(Mx-i))try:print(m.decode())except:continue
不过结果却爆出来许多值,只需要找到结尾是‘}’
的就欧克了