引言
无
[watevrCTF 2019]ECC-RSA
看到标题就有点怕了,ECC椭圆曲线加密,学过一点皮毛,没做过题,找wp
加密代码如下:
from fastecdsa.curve import P521 as Curve
from fastecdsa.point import Point
from Crypto.Util.number import bytes_to_long, isPrime
from os import urandom
from random import getrandbits
def gen_rsa_primes(G):
urand = bytes_to_long(urandom(521//8))
while True:
s = getrandbits(521) ^ urand
Q = s*G
if isPrime(Q.x) and isPrime(Q.y):
print("ECC Private key:", hex(s))
print("RSA primes:", hex(Q.x), hex(Q.y))
print("Modulo:", hex(Q.x * Q.y))
return (Q.x, Q.y)
flag = int.from_bytes(input(), byteorder="big")
ecc_p = Curve.p
a = Curve.a
b = Curve.b
Gx = Curve.gx
Gy = Curve.gy
G = Point(Gx, Gy, curve=Curve)
e = 0x10001
p, q = gen_rsa_primes(G)
n = p*q
file_out = open("downloads/ecc-rsa.txt", "w")
file_out.write("ECC Curve Prime: " + hex(ecc_p) + "\n")
file_out.write("Curve a: " + hex(a) + "\n")
file_out.write("Curve b: " + hex(b) + "\n")
file_out.write("Gx: " + hex(Gx) + "\n")
file_out.write("Gy: " + hex(Gy) + "\n")
file_out.write("e: " + hex(e) + "\n")
file_out.write("p * q: " + hex(n) + "\n")
c = pow(flag, e, n)
file_out.write("ciphertext: " + hex(c) + "\n")
后来发现,关于椭圆曲线加密算法,本题用到的其实就是威尔斯特拉斯方程(Weierstrass):
y
2
=
x
3
+
a
x
+
b
y^2 = x^3 + ax + b
y2=x3+ax+b
代码中a
,b
就是方程中的a,b,ecc_p
指的是椭圆曲线加密算法
y
2
=
x
3
+
a
x
+
b
(
m
o
d
p
)
y^2 = x^3 + ax + b(mod\space p)
y2=x3+ax+b(mod p),具体可以参照fastecdsa库的官方文档
顺带一提,这个库只能在Linux环境下安装
代码中的G
指的是基点,也就是加密最开始的那个点;Gx
,Gy
即为基点的横纵坐标
然后把G
放到生成RSA加密所需的p,q的函数gen_rsa_primes(G)
中,先随机生成了一个s
,然后Q = s*G
中Q
也是椭圆曲线上的点,只是在这个阿贝尔群中作数乘运算,其中s
应该小于G的阶数
最后,p,q即为Q点的横纵坐标
显然G点满足椭圆曲线方程,而n=pq,其中n为已知量,即有如下方程组:
{
q
2
=
p
3
+
a
p
+
b
(
m
o
d
P
)
n
=
p
q
\begin{cases} q^2 = p^3 + ap + b\space(mod\space P)\\ n = pq \end{cases}
{q2=p3+ap+b (mod P)n=pq
由于变量重复,记ecc_p
为
P
P
P
解方程
n
2
=
p
5
+
a
p
3
+
b
p
2
(
m
o
d
P
)
n^2 = p^5 + ap^3 + bp^2\space(mod\space P)
n2=p5+ap3+bp2 (mod P)即可得到p
sage代码如下:
其中R.<x> = PolynomialRing(GF(P))
即为在有限域
G
F
(
P
)
GF(P)
GF(P)中求解,其实就是
m
o
d
P
mod\space P
mod P的意思
得到三个解,显然第一和第三个不是质数,只可能是第二个
然后就是常规的RSA解密,解密代码如下:
from Crypto.Util.number import *
import gmpy2
list_p = [6813140671672694477701511883397067876211159809088064490593325584756562268820329988116480298456252746748095410666300132267213094431909630229631434972416225885, 4573744216059593260686660411936793507327994800883645562370166075007970317346237399760397301505506131100113886281839847419425482918932436139080837246914736557, 1859314969084523636298100850823722544590555574470838518640063093117116629078281861281849586432508721074855657736668366212762253040197962779753163192386773060]
for p in list_p:
print(gmpy2.is_prime(p))
p = 4573744216059593260686660411936793507327994800883645562370166075007970317346237399760397301505506131100113886281839847419425482918932436139080837246914736557
n = 0x118aaa1add80bdd0a1788b375e6b04426c50bb3f9cae0b173b382e3723fc858ce7932fb499cd92f5f675d4a2b05d2c575fc685f6cf08a490d6c6a8a6741e8be4572adfcba233da791ccc0aee033677b72788d57004a776909f6d699a0164af514728431b5aed704b289719f09d591f5c1f9d2ed36a58448a9d57567bd232702e9b28f
q = n//p
c = 0x3862c872480bdd067c0c68cfee4527a063166620c97cca4c99baff6eb0cf5d42421b8f8d8300df5f8c7663adb5d21b47c8cb4ca5aab892006d7d44a1c5b5f5242d88c6e325064adf9b969c7dfc52a034495fe67b5424e1678ca4332d59225855b7a9cb42db2b1db95a90ab6834395397e305078c5baff78c4b7252d7966365afed9e
e = 0x10001
phi = (p-1)*(q-1)
d = inverse(e, phi)
m = pow(c, d, n)
print(long_to_bytes(m))
结果为:
结语
终于把1分题刷完了
下一道题还得研究一下
希望继续坚持