同RSA(Ron Rivest,Adi Shamir,Len Adleman三位天才的名字)一样,ECC(Elliptic Curves Cryptography,椭圆曲线密码编码学)也属于公开密钥算法。RSA算法是基于大整数因子分解问题(IFP),ECC算法是基于椭圆曲线上离散对数计算问题(ECDLP)。
要想理解ECC,那么椭圆曲线一定是一个不能回避的问题。不过请放心,并不需要了解很多,够用即可,甚至很多细节也都不用深究。椭圆曲线其实是一类曲线,而且并不像其名字所说的那样,它和我们高中所学的椭圆公式并不一样。
一条椭圆曲线是在射影平面上满足方程 Y2Z+a1XYZ+a3YZ2=X3+a2X2Z+a4XZ2+a6Z3所有点的集合,且曲线上的每个点都是非奇异(或光滑)的。
是不是看着像天书?确实是的,因为我其实并没有介绍里面的名词比如射影平面,因为我们不需要了解那么多,因为并不是所有的椭圆曲线都适用与加解密。在密码学中,也只用到椭圆曲线的子集如y2=x3+ax+b,这是最简单的一种,而且我们使用高中数学也能明白其图像长什么样子。
其图像如下所示:
从上图中,我们可以看到,这条曲线关于x轴对称(但是要注意,这只是一类特殊的椭圆曲线),并且每一点都有切线。下面就基于这一类椭圆曲线描述一系列定义和性质。
首先,我们还需要定义一些小小的特殊成分,正如同在小学数学中我们有零,在初中数学平面直角坐标系中我们有原点一样,我们这里也有一个特殊的点无穷远点 O∞并称为零元,你可以顾名思义想象它在哪里,显然我们画不出来,但是想象不出来也没关系(虚数i大家也难以想象出来吧),我们只需要会运算就可以。
接着需要基于这个曲线定义一些运算,最重要的无疑是加法,而基于加法我们可以衍生出减法和乘法。
首先是加法, 对于平面上两点P和Q,我们可以这么定义其和R以及和对应的负值 -R(我们称之为负元)。
而如果 P和Q是同一点,那么直线PQ就是在该点的切线(回想一下之前所讲的任何一点切线都存在),那么和也就同样可以得到,并且通过这样的方式,我们可以将和拓展到2P、3P…nP,因此我们也定义出了乘法,而-R的存在也使得我们可以定义减法。
好了,在上面,我们定义了加法减法和乘法,当然,尽管我们没有定义除法,但很容易想到除法可以反过来由乘法推算出。确实如此,我们小学中除法也是这么来的。但是在这里,除法并没有什么除法法则帮我们计算,因此除法远比乘法难以计算。
对于ECC,我们对椭圆曲线的知识背景了解就只需要这么多就可以了。
有限域是什么呢?简单地说,就是我们从一个集合中选一个子集,那么这就构成了一个有限域。那么为什么我们在这里需要有限域呢?这个问题不难回答,椭圆曲线的点是属于实数的,而计算机并没有办法包含所有的实数的,甚至于很多简单的小数都没办法包含,因此,我们需要限制一个在有限域内的椭圆曲线。
因此,我们可以定义以下的有限域Fp,其只包含有限个取值。
因此,我们可以定义如下在有限域Fp上的的椭圆曲线如下所示。
有方程y2=(x3+ax+b)(mod p),其中4a3+27b2≠0 (mod p),所有满足上述方程的有限域内的点(x,y)并加上O∞无穷远点构成了Ep(a,b)。
我们以y2=x3+x+1 (mod 23)为例,其在有限域上的的椭圆曲线图像如下所示:
可见,我们现在所看见的只有一系列离散的点。
在有限域上的椭圆曲线自然也是有其加法的,但是已经不是几何意义上的加法了,在这里直接给出结论,因为这其实已经不需要过于深究了。
最后,我们讲一下椭圆曲线上的点的阶。对于椭圆曲线上一点P,若存在最小的正整数n,使得nP=O∞,则称n为P的阶。若不存在这样的n,我们则称P是无限阶的。但是幸运的是,对于有限域上的的所有点都是有阶的。
大体上是说,给出一个曲线:y^2=x^3+ax+b
,
确定下来a和b,然后找一个在曲线上的点G(x1,y1),
然后自己随机生成一个k(私钥),
然后生成公钥K=kG
,
注意:这里的kG可不是k*G这么简单,这是几何意义上的:
然后把公钥给出去,私钥留给自己。
和RSA差不多,重点应该是在于如何求K。
核心公式:
x3≡t^2-x1-x2(mod p)
y3≡t(x1-x3)-y1(mod p)
其中
若P=G 则 t=(3x^2+a)/2y1
若P≠G 则 t=(y2-y1)/(x2-x1)
a=16546484
p=15424654874903
def egcd(t, b):
if t == 0:
return (b, 0, 1)
else:
g, y, x = egcd(b % t, t)
return (g, x - (b // t) * y, y)
def modinv(o, m):
g, x, y = egcd(o, m)
if g != 1:
raise Exception('modular inverse does not exist')
else:
return x % m
def ecc_m(x1,y1,x2,y2):
if ((x1 == x2) & (y1 == y2)):
fenzi=3*x1*x1+a
fenmu=2*y1
else:
fenzi = y2 - y1
fenmu = x2 - x1
m=(abs(fenzi) * modinv(abs(fenmu), p)) % p
if ((fenzi >= 0 & fenmu >= 0) | (fenzi < 0 & fenmu < 0)):
return m
else:
return p - m
def ecc_x(x1,x2,m):
result_x = m*m-x1-x2
if result_x>0:
return result_x%p
else:
p1=p
if abs(result_x)>p1:
shang=abs(result_x)/p
p1=shang*p+p
return p1+result_x
def ecc_y(x1,result_x,y1,m):
result_y = m*(x1-result_x)-y1
if result_y>0:
return result_y%p
else:
p1 = p
if abs(result_y) > p1:
shang = abs(result_y) / p
p1 = shang * p + p
return p1 + result_y
def ecc_result_x(x1,y1,x2,y2):
m = ecc_m(x1,y1,x2,y2)
result_x=ecc_x(x1,x2,m)
return result_x
def ecc_result_y(x1,y1,x2,y2):
m = ecc_m(x1,y1,x2,y2)
result_x = ecc_x(x1, x2, m)
result_y=ecc_y(x1, result_x, y1, m)
return result_y
x1=x2=x3=6478678675
y1=y2=5636379357093
n=546767
while(n>0):
x2=ecc_result_x(x1,y1,x2,y2)
y2=ecc_result_y(x1,y1,x3,y2)
x3=x2
n-=1
print x2,y2
result = x2+y2
flag = "XUSTCTF{%s}"%result
print(flag)
运行后即可得到flag
个人认为ECC椭圆加密算法的难点关键还是在于中间涉及到数论的知识,本人较菜,还需学习。