这次 medium 分类题量是最多的,内容方面是最丰富的,两极分化比较严重。
有脑筋急转弯的,有考察 SageMath API 使用的,有 MISC 题目混进来的……
总之 medium 分类最难的比 tough 还要更难……
Derik 题目描述 已知 $O_0, O_1, O_2, O_3$ 的值,以及 $C_0, C_1, C_2, C_3, C_4, C_5, C_6, C_7$ 的值,未知 $e, d, p, q, r$ 的值。
有如下条件:
$e, d, p, q, r$ 均为素数
$C_0 p - C_1 q \ge 0$
$C_2 p - C_3 r \ge 0$
$C_4 r - C_5 p \ge 0$
$(C_0 p - C_1 q) ^ e + (C_2 q - C_3 r) ^ e + (C_4 r - C_5 p) ^ e = d (C_0 p - C_1 q) (C_2 q - C_3 r) (C_4 r - C_5 p)$
$C_6 e - C_7 d = O_3$
RSA 中,$N = edpqr$,加密指数为 65537,对 flag 加密得到 $c$,试求 flag。
我的解答 首先从最后一个式子出发:因为 $e, d$ 均为素数,所以两者互素。
代入具体值分析:$C_6 = 10543, C_7 = 4, O_3 = 31337$,直接枚举 $e$,并求得 $d$,并作素性检验,会发现有很多组 $(e, d)$ 满足等式。这种题一般是要求最简单的,所以应该是 $(e, d) = (3, 73)$
然后记
就有:
这是三次齐次方程,等价于一个椭圆曲线。更多可以参考 SageMath 手册:
https://doc.sagemath.org/html/en/reference/arithmetic_curves/sage/schemes/elliptic_curves/constructor.html#sage.schemes.elliptic_curves.constructor.EllipticCurve_from_cubic
然后就可以依葫芦画瓢地构造一个椭圆曲线并求得生成元:
1 2 3 4 5 6 7 8 9 R.<x,y,z> = QQ[] cubic = x^3 + y^3 + z^3 - 73 * x * y * z P = [1 ,-1 ,0 ] E = EllipticCurve_from_cubic(cubic, P, morphism=False ) f = EllipticCurve_from_cubic(cubic, P, morphism=True ) finv = f.inverse() R = E.gens()[0 ] PP = f(P) print (finv(R))
注意 $(A, B, C) = (1, -1, 0)$ 仍然为我们三次齐次方程的非零解。并且,三次齐次方程关于未知量 $(A, B, C)$ 对称。
然后很惊讶地发现,结果为:
1 (2848691279889518/1391526622949983 : 89200900157319/1391526622949983 : 1)
也就是恰好为题目所给的 $O$ 数组的 $O_0, O_1, O_2$!
也就是说,即使(e, d)还有那么多组解,即使椭圆曲线上还有其他的点(生成元的倍点),我们都不 care,只 care 这个能跟出题的对上脑电波的这一组解 WTF
至此,我们有 3 个关于 $(p, q, r)$ 的线性方程,直接枚举 $(O_0, O_1, O_2)$ 作为所有的排列作为右边的东西解线性方程就行了(事实上连排列都压根不用做,他那个等式和 O 的顺序完全就是对上的 )
1 2 3 4 5 6 7 8 9 10 11 12 13 import itertoolsO = [1391526622949983 , 2848691279889518 , 89200900157319 ] C = [5960650533801939766973431801711817334521794480800845853788489396583576739362531091881299990317357532712965991685855356736023156123272639095501827949743772 , 6521307334196962312588683933194431457121496634106944587943458360009084052009954473233805656430247044180398241991916007097053259167347016989949709567530079 , 1974144590530162761749719653512492399674271448426179161347522113979158665904709425021321314572814344781742306475435350045259668002944094011342611452228289 , 2613994669316609213059728351496129310385706729636898358367479603483933513667486946164472738443484347294444234222189837370548518512002145671578950835894451 , 8127380985210701021743355783483366664759506587061015828343032669060653534242331741280215982865084745259496501567264419306697788067646135512747952351628613 , 5610271406291656026350079703507496574797593266125358942992954619413518379131260031910808827754539354830563482514244310277292686031300804846114623378588204 , 10543 , 4 ] A = matrix(ZZ, [[ C[0 ], -C[1 ], 0 ], [ 0 , C[2 ], -C[3 ]], [-C[5 ], 0 , C[4 ]]]) for op in itertools.permutations(O): b = vector(ZZ, op) x = A.solve_right(b) print (x)
最后只用老老实实解密就行了:
1 2 3 4 5 6 7 8 9 10 11 12 13 from Crypto.Util.number import *p, q, r = (9758621034843917661145412977193922808892309951663464821517963113005483457886774294910761723767526582514514505278091600074371768233672585649562672245905811 , 8919642442779618620315315582249815126044061421894622037450496385178083791083142991676417756698881509754110765444929271564991855378540939292428839562446571 , 6736304432663651651650099104581016800112378771266600017972326085742513966258250417227421932482058281545032658577816441378170466639375931780967727070265551 ) e, d = (3 , 73 ) c = 80607532565510116966388633842290576008441185412513199071132245517888982730482694498575603226192340250444218146275844981580541820190393565327655055810841864715587561905777565790204415381897361016717820490400344469662479972681922265843907711283466105388820804099348169127917445858990935539611525002789966360469324052731259957798534960845391898385316664884009395500706952606508518095360995300436595374193777531503846662413864377535617876584843281151030183895735511854 N = e * d * p * q * r phi = (e-1 )*(d-1 )*(p-1 )*(q-1 )*(r-1 ) d = inverse(65537 , phi) m = pow (c, d, N) print (long_to_bytes(m))
得到 flag 为:
1 CCTF{____Sylvester____tHE0r3m_Of_D3r!va7i0n!}
Barak 题目描述 题目在 $\mathbb{Z}/p\mathbb{Z}$ 上定义了一个曲线:
并定义该曲线上的加法运算:假设点为 $P_1(x_1, y_1)$ 和 $P_2(x_2, y_2)$,定义 $P_3 = P_1 + P_2$,且 $P_3(x_3, y_3)$:
在这条曲线上,有两个点:随机点 $P$ 和倍点 $Q = m P$ 已知,求未知倍数 $m$。
我的解答 首先尝试对这条曲线做一定的分析:把 $c$ 和 $d$ 设为比较小的值,然后随机弄一个曲线上的点不断乘倍数,求阶,发现如下性质:
在分母为 0 的时候,求和运算会报错,因此猜测这条曲线上的零点应该是这时候的点(无法用 $(x, y)$ 表示出)
如果 $P$ 为 $(x, y)$,那么 $-P$ 为 $(y, x)$
但是折腾了一番,并没有发现什么可以等价到椭圆曲线 Weierstrass 形式上的映射。等风哥哥提出可以作代换 $u = x+y, v = xy$,但是 $v^2$ 这一项出不来,而且这也不满足上面提到的第二个性质。
然后查了下 SageMath 的手册发现,和 Derik 类似,只需要用到 SageMath 中关于三次齐次方程的椭圆曲线构造法就行了:
https://doc.sagemath.org/html/en/reference/arithmetic_curves/sage/schemes/elliptic_curves/constructor.html#sage.schemes.elliptic_curves.constructor.EllipticCurve_from_cubic
不过我们这里只有一个二次的,需要再引入一个变量 $z$ 来把它变成齐次式:
当 $z=1$ 时即为原方程。
然后就通过映射,将原曲线中的点映射到椭圆曲线上,看了一下构造出来的椭圆曲线的阶是光滑的,所以直接求个离散对数就行了。代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 p = 73997272456239171124655017039956026551127725934222347 c = 1 d = 68212800478915688445169020404812347140341674954375635 Zp = Zmod(p) R.<xx,yy,zz> = Zp[] cubic = xx^3 + yy^3 + c * zz^3 - d * xx * yy * zz EC = EllipticCurve_from_cubic(cubic, morphism=False ) mf = EllipticCurve_from_cubic(cubic, morphism=True ) print (EC.order())P = (71451574057642615329217496196104648829170714086074852 , 69505051165402823276701818777271117086632959198597714 ) Q = (40867727924496334272422180051448163594354522440089644 , 56052452825146620306694006054673427761687498088402245 ) PP = mf(P) QQ = mf(Q) dd = PP.discrete_log(QQ) print (f'{PP.order() = } ' )from Crypto.Util.number import *print (dd)
不过要注意,直接把上面求得的 dd
作 long_to_bytes
会得到乱码,这是因为随机点 PP
不是椭圆曲线的生成元。所以我们还需要加上 PP
阶的倍数去枚举:
1 2 3 4 5 6 n = 1780694557271320552511299360138314441283923223949197 p = 73997272456239171124655017039956026551127725934222347 o = 3083219685676632130193959041477461850061047352503612 from Crypto.Util.number import *for i in range (100 ): print (long_to_bytes(n + i * o))
得到 flag 为:
1 CCTF{_hE5S!4n_f0rM_0F_3CC!!}
学习一个:椭圆曲线的 Hessian 形式
https://en.wikipedia.org/wiki/Hessian_form_of_an_elliptic_curve
所以直接拿那个给出的形式代回 Weierstrass 形式也彳亍
Risk 题目描述 未知 $p, q, r, s, m$ 满足:
$m \ge 2$
$p, q$ 均为 1024 位素数
$p = a^m + r$
$q = b^m + s$
$r, s$ 均为 $m^2 - m + 2$ 位正整数
RSA 中,$N=pq$,$e=rs$,加密明文得到密文 $c$,试求明文。
我的解答 首先 $N = pq = (a^m+r)(b^m+s) = (ab)^m + r b^m + s a^m + rs > (ab)^m$
如果 $m \ge 3$,只要 $m$ 不是太大,那么 $(ab+1)^m = (ab)^m + m(ab)^{m-1} + 3m (ab) + 1$ 是能够大过 $N$ 的,所以此时对 $N$ 开 $m$ 次方根,就能得到 $ab$ 的值。
如果 $m=2$,虽然对 $N$ 开 $m$ 次方根不是 $ab$,但是也差得不远了。
但是我们还是需要知道具体的 $a$ 或者 $b$,还得对 $ab$ 的所有约数进行遍历,如果 $ab$ 难分解的话一下子就……(坠痛苦的)
另一个思路是枚举 $m$ 的同时,去枚举 $r$ 的值,通过 $p$ 是 $N$ 的约数,用 Coppersmith 方法求出 $p$。
而且我们有 $e=rs$ 也是已知的,那么我们就可以知道 $m$ 是多少,才能生成出 $e$ 来,并枚举 $r$ 的值。
题目中的 $e$ 是 28 位,$28 = 2 (m^2 - m + 2)$ 解得 $m=4$。
然后枚举 $e$ 的所有 14 位因子,发现就两个:
然后一开始想着是拿一个作为 $r$ 去跑 Coppersmith 方法,但是注意了:别看着这里的 $a$ 和 $b$ 是小的,但是它们的次数 $m$ 比较大;而 Coppersmith 方法所适用的 $x$ 所满足的条件是:
而这里 $\delta$ 就是 Coppersmith 中原本多项式的次数。好家伙,这一来一去,Coppersmith 了个寂寞,所以这里是不能用 small_roots
滴。
所以这个时候需要回看 $N$ 的表示式:因为 $ab$ 知道 $r$ 知道 $s$ 知道,所以可以关于 $a^m$ 和 $b^m$ 建立方程并解方程。代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 pkey = (150953688 , 373824666550208932851344358703053061405262438259996622188837935528607451817812480600479188884096072016823491996056842120586016323642383543231913508464973502962030059403443181467594283936168384790367731793997013711256520780338341018619858240958105689126133812557401122953030695509876185592917323138313818881164334490044163316692588337720342646339764174333821950301279825316497898035760524780198230860089280791887363472060435443944632303774987556026740232641561706904946900169858650106994947597642013168757868017723456208796677559254390940651802333382820063200360490892131573853635471525711894510477078934343423255983 ) enc = 275574424285842306309073814038154403551700455145115884031072340378743712325975683329051874910297915882286569143815715537085387363420246497061870251520240399514896001311724695996978111559476733709139080970977190150345474341853495386364275702356438666152069791355990718058189043717952080875207858163490627801836274404446661613239167700736337269924479349700031535265765885064606399858172168036794462235707003475360358004643720927563261787867952228496769300443415094124132722170498229611285689671203272698693505808912907778910378274197503048226322090611405601517624884408718689404556983397217070272851442351897456769883 e, N = pkey m = 4 r = 10728 s = 14071 ab = floor(N^(1 /m)) PR.<x, y> = PolynomialRing(ZZ) f1 = x * y - ab^m f2 = (x + r) * (y + s) - N PR.<y> = PolynomialRing(ZZ) f3 = 10728 *y^2 - 511086150867555670991182215716996884365017094048011334498502864759458604412974525192545554902255616748785034586283311417267948637161905335789524940513213807388789747893057116518524986565352587286484213819873973314973576845522082944759362821020072842990178502502907835104629002180230922192278601476281549539304919 *y + 5260086883027989894151266471310659627033447768756412470819138590823035454528439414529342666788115829348723355876515825478765835689971978836816254977610642160178724965865849006430519169265825342385264354073331979931090503900140796473000025308521505151693828876495191201072094916519467807477939653879213738285370121752035575512256453146199781476491291347483720934255498391686419228296642359873666276793532997868425427822887434754439647641247870006446823852067931010198965229083394533490439946570165059178219301430708237320778256595039419216917256059584687394490563748927035618459815041808985900104721604927460617006077696 print (f3.roots())
然后就能解得 $b^m$,也就求得 $q=b^m + s$……到这里还没完!
然后就是会发现 $p-1$ 和 $e$ 不互素,以及 $q-1$ 和 $e$ 不互素!所以还要套用一个开方+中国剩余定理解密。具体操作原理详见:
[*CTF 2021] Crypto - little case (x) - ZM.J 的文章 - 知乎https://zhuanlan.zhihu.com/p/345235655
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 from Crypto.Util.number import *import itertoolspkey = (150953688 , 373824666550208932851344358703053061405262438259996622188837935528607451817812480600479188884096072016823491996056842120586016323642383543231913508464973502962030059403443181467594283936168384790367731793997013711256520780338341018619858240958105689126133812557401122953030695509876185592917323138313818881164334490044163316692588337720342646339764174333821950301279825316497898035760524780198230860089280791887363472060435443944632303774987556026740232641561706904946900169858650106994947597642013168757868017723456208796677559254390940651802333382820063200360490892131573853635471525711894510477078934343423255983 ) enc = 275574424285842306309073814038154403551700455145115884031072340378743712325975683329051874910297915882286569143815715537085387363420246497061870251520240399514896001311724695996978111559476733709139080970977190150345474341853495386364275702356438666152069791355990718058189043717952080875207858163490627801836274404446661613239167700736337269924479349700031535265765885064606399858172168036794462235707003475360358004643720927563261787867952228496769300443415094124132722170498229611285689671203272698693505808912907778910378274197503048226322090611405601517624884408718689404556983397217070272851442351897456769883 e, N = pkey m = 4 r = 10728 s = 14071 bm = 15040222622096320078383580808680733765955114958694997949647342925417877088612792495485641348591026281373930569798925789027166056695954731923306109646611840570310396750856642056018981080439916663195842593441587057719678555907050674529272376248049062724657792390788687452049496308886252188791975094655675924736 q = bm + s p = N // q def get_oneroot (p, e ): while True : Zp = Zmod(p) g = Zp.random_element() g = g^((p-1 ) // e) for mult in divisors(e): if (mult != e): g2 = g^mult if (g2 == 1 ): break else : return g def decrypt (p, c, e ): w = gcd(e, p-1 ) e1, p1 = e // w, (p-1 ) // w d = inverse_mod(e1, p1) c1 = pow (c, d, p) g, a, b = xgcd(p1, w) g = get_oneroot(p, w) m = pow (c1, b, p) return [ZZ(m * g^i) for i in range (w)] mp_list = decrypt(p, enc, e) print ('Find root p OK' )mq_list = decrypt(q, enc, e) print ('Find root q OK' )for mp, mq in itertools.product(mp_list, mq_list): m = crt([mp, mq], [p, q]) msg = long_to_bytes(int (m)) if (b'CCTF' in msg): print (msg)
得到 flag 为:
1 CCTF{S!mP1E_A7t4cK_0n_SpEc1aL-5trucTur3D_RSA_pR1me5!}