经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 其他 » 网络安全 » 查看文章
浅析椭圆曲线加密算法(ECC)
来源:cnblogs  作者:KRDecad3  时间:2019/9/16 9:14:06  对本文有异议

本文首发于先知社区,原文链接:https://xz.aliyun.com/t/6295

数学基础

黎曼几何中的“平行线”

欧几里得《几何原本》中提出五条公设:

  1. 过相异两点,能作且只能作一直线。
  2. 有限直线可以任意地延长。
  3. 以任一点为圆心、任意长为半径,可作一圆。
  4. 凡直角都相等。
  5. 两直线被第三条直线所截,如果同侧两内角和小于两个直角, 则两直线作会在该侧相交(平行公设)。

《几何原本》中只有第29条命题,

一条直线与两条平行直线相交,则所成的内错角相等,同位角相等,且同旁内角之和等于两直角

才用到了第五公设,其他命题并没有使用到,因此一些数学家提出疑问:第五公设能否不作为公设,而作为一条定理?能否靠前四条公设证明之?因此出现了长期的关于“平行线理论”的讨论。欧氏几何讲“过直线外一点有且只有一条直线与已知直线平行”,后面就有个罗氏几何(罗巴切夫斯基)讲“过直线外一点至少存在两条直线和已知直线平行”,那么是否有“过直线外一点,不能做直线和已知直线平行?”,黎曼几何就回答了这个问题。

黎曼几何中不承认平行线的存在,即在同一平面内任何两条直线都有公共点(交点)。另一条公设讲:直线可以无限延长,但总的长度是有限的。

黎曼几何也被称为椭圆几何。椭圆曲线就是基于黎曼几何的“平行线理论”。

定义平行线相较于无穷远点P∞,使平面上所有直线都有唯一的交点。

clipboard.png

无穷远点的性质:

  • 一条直线只有一个无穷远点。
  • 平面上一组相互平行的两条直线有公共的无穷远点。
  • 平面上任何相交的直线有不同的无穷远点(否则就会存在两个交点)。
  • 平面上全体无穷远点构成一条无穷远直线
  • 平面上全体无穷远点与全体平常点构成射影平面

射影平面坐标系

射影平面坐标系是对笛卡尔平面直角坐标系的扩展。普通平面直角坐标系无法表示无穷远点,因此为了表示无穷远点的坐标,产生了射影平面坐标系。

射影平面点的表示:

对普通平面直角坐标系上的点A(x,y),令x=X/Z,y=Y/Z(Z≠0),则点A在射影平面上表示为(X:Y:Z)。

那么对于平面直角做标记上的点(1,2),在射影平面上坐标为(Z:2Z:Z)Z≠0。

直线方程表示为aX+bY+cZ=0。

两条平行线L1: X+2Y+3Z=0与L2: X+2Y+Z=0,因为L1||L2,所以Z=0,X+2Y=0,所以无穷远点坐标为(-2Y:Y:0)。

椭圆曲线方程

一条椭圆曲线在射影平面满足一齐次方程——威尔斯特拉斯方程:

的所有点的集合,且曲线上的每个点都是非奇异(光滑)的。

椭圆曲线并不是椭圆,是由椭圆曲线的描述方程类似于计算椭圆周长的方程而得名。

“非奇异”或“光滑”,可以理解为,满足方程的任意一点都存在切线。虽然有的方程满足上面的形式,但是并不是椭圆曲线。

椭圆曲线上有一个无穷远点(0:1:0)且满足方程。

如何把椭圆曲线放到平面直角坐标系呢?射影平面坐标系只多了个无穷远点,因此求出平面直角坐标系上椭圆曲线所有平常点组成的曲线方程,再加上无穷远点,就构成了椭圆曲线。

把x=X/Z,y=Y/Z代入威尔斯特拉斯方程,得到普通方程:

image.png

椭圆曲线上的群操作

假设用加法符号“+”表示群操作,给定两个点及其坐标,P(x1,y1),Q(x2,y2),计算第三个点R坐标:

P+Q=R (x1,y1)+(x2,y2)=(x3,y3)

在椭圆曲线上定义阿贝尔群,其运算法则:

任意选取椭圆曲线上两点P、Q(若P、Q两点重合,则作P点的切线)作直线交于椭圆曲线的另一点R',过R'作y轴平行线交于R,规定P+Q=R。

相异点相加P+Q:

clipboard.png

相同点相加P+P:

clipboard.png

若有k个相同的P点相加,记作kP。

有限域上的椭圆曲线

实数域上的椭圆曲线是连续的,并不适用于加密,考虑到加密算法的可实现性,要把椭圆曲线定义在有限域上,使之变成离散的点。

给定一个有限域Fp:

  • Fp只有p(p为素数)个元素0,1,2...p-2,p-1;
  • Fp的加法(a+b)法则是a+b≡c(mod p);
  • Fp的乘法(a×b)法则是a×b≡c(mod p);
  • Fp的除法(a÷b)法则是a÷b≡c(mod p),即a×b^-1≡c(mod p),b^-1为b的逆元;
  • Fp的单位元是1,零元是0;
  • Fp域内运算满足交换律、结合律、分配律。

并非所有的椭圆曲线都适合加密。下面定义一类适合加密的椭圆曲线:

椭圆曲线Ep(a,b),p为质数,x,y∈[0,p-1]:

image.png

选择两个满足下列约束条件的小于p的非负整数a、b:

image.png

  • 无穷远点O∞是零元,有O∞+O∞=O∞,O∞+P=P;
  • P(x,y)的负元是(x,-y),有P+(-P)=O∞;
  • P(x1,y1),Q(x2,y2)和R(x3,y3)有如下关系:
    image.png
    其中若P=Q则
    image.png
    ,若P≠Q则
    image.png
    k为直线斜率。

椭圆曲线上点的阶

如果椭圆曲线上一点P,存在最小的正整数n使得数乘nP=O∞,则称n为P的阶,若n不存在,则P为无限阶。

在有限域上定义的椭圆曲线,所有点的阶n都是存在的。

加密与解密

等式Q=dG(Q,G为Ep(a,b)上的点,d为小于n(n是点G的阶)的整数),在有限域上的椭圆曲线,给定d和G,根据有限域上的加法法则,很容易计算出Q;但给定Q和G,很难计算出d。这就是椭圆曲线的离散对数难题。

点G称为基点,d为私钥,Q为公钥。

加解密步骤

  1. Alice选定一条椭圆曲线Ep(a,b),并取曲线上一点作为基点G。
  2. Alice选择一个d作为私钥,并生成公钥Q=dG。
  3. Alice将曲线Ep(a,b)和点Q、G发给Bob。
  4. Bob收到信息后,将待传输的明文编码到曲线Ep(a,b)上的一点M,并选择一个随机整数k(k<n)。
  5. Bob计算点C1=M+kQ;C2=kG。
  6. Bob将C1 C2发给Alice。
  7. Alice收到信息后,计算C1-dC2=M+kQ-d(kG)=M+k(dG)-d(kG)=M,得到点M,再对点M进行解码就得到明文。

攻击者从信道中截取信息,只能得到Ep(a,b),Q,G,C1,C2,而通过Q、G求d或通过C1、C2求k都是困难的,因此攻击者无法获取到明文。

密码学中描述一条有限域上的椭圆曲线常用到六个参量:
T=(p,a,b,G,n,h)

p、a、b用来确定一条椭圆曲线,G为基点,n为点G的阶,h是有限域椭圆曲线上所有点的个数m与n相除得到的整数部分。

这几个参量取值的选择,直接影响了加密的安全性。一般满足如下条件:

  1. p越大越好,但越大,计算速度会变慢,200位左右可满足一般安全需求;
  2. p≠n×h;
  3. image.png 1≤t<20;
  4. image.png
  5. n为素数;
  6. h≤4。

Demo

这是参考网上的资料实现的简易ECC加解密Demo:

  1. # -*- coding:utf-8 -*-
  2. def get_inverse(value, p):
  3. """
  4. 求逆元
  5. :param value: 待求逆元的值
  6. :param p: 模数
  7. """
  8. for i in range(1, p):
  9. if (i * value) % p == 1:
  10. return i
  11. return -1
  12. def get_gcd(value1, value2):
  13. """
  14. 辗转相除法求最大公约数
  15. :param value1:
  16. :param value2:
  17. """
  18. if value2 == 0:
  19. return value1
  20. else:
  21. return get_gcd(value2, value1 % value2)
  22. def get_PaddQ(x1, y1, x2, y2, a, p):
  23. """
  24. 计算P+Q
  25. :param x1: P点横坐标
  26. :param y1: P点纵坐标
  27. :param x2: Q点横坐标
  28. :param y2: Q点纵坐标
  29. :param a: 曲线参数
  30. :param p: 曲线模数
  31. """
  32. flag = 1 # 定义符号位(+/-)
  33. # 如果P=Q,斜率k=(3x^2+a)/2y mod p
  34. if x1 == x2 and y1 == y2:
  35. member = 3 * (x1 ** 2) + a # 分子
  36. denominator = 2 * y1 # 分母
  37. # 如果P≠Q, 斜率k=(y2-y1)/(x2-x1) mod p
  38. else:
  39. member = y2 - y1
  40. denominator = x2 - x1
  41. if member * denominator < 0:
  42. flag = 0 # 表示负数
  43. member = abs(member)
  44. denominator = abs(denominator)
  45. # 化简分子分母
  46. gcd = get_gcd(member, denominator) # 最大公约数
  47. member = member // gcd
  48. denominator = denominator // gcd
  49. # 求分母的逆元
  50. inverse_deno = get_inverse(denominator, p)
  51. # 求斜率
  52. k = (member * inverse_deno)
  53. if flag == 0:
  54. k = -k
  55. k = k % p
  56. # 计算P+Q=(x3,y3)
  57. x3 = (k ** 2 - x1 - x2) % p
  58. y3 = (k * (x1-x3) -y1) % p
  59. return x3, y3
  60. def get_order(x0, y0, a, b, p):
  61. """
  62. 计算椭圆曲线的阶
  63. """
  64. x1 = x0 # -P的横坐标
  65. y1 = (-1 * y0) % p # -P的纵坐标
  66. temp_x = x0
  67. temp_y = y0
  68. n = 1
  69. while True:
  70. n += 1
  71. # 累加P,得到n*P=0∞
  72. xp, yp = get_PaddQ(temp_x, temp_y, x0, y0, a, p)
  73. # 如果(xp,yp)==-P,即(xp,yp)+P=0∞,此时n+1为阶数
  74. if xp == x1 and yp == y1:
  75. return n+1
  76. temp_x = xp
  77. temp_y = yp
  78. def get_dot(x0, a, b, p):
  79. """
  80. 计算P和-P
  81. """
  82. y0 = -1
  83. for i in range(p):
  84. # 满足适合加密的椭圆曲线条件,Ep(a,b),p为质数,x,y∈[0,p-1]
  85. if i**2 % p == (x0**3 + a*x0 + b) % p:
  86. y0 = i
  87. break
  88. # 如果找不到合适的y0返回False
  89. if y0 == -1:
  90. return False
  91. # 计算-y
  92. x1 = x0
  93. y1 = (-1*y0) % p
  94. return x0, y0, x1, y1
  95. def get_graph(a, b, p):
  96. """
  97. 画出椭圆曲线散点图
  98. """
  99. xy = []
  100. # 初始化二维数组
  101. for i in range(p):
  102. xy.append(['-' for i in range(p)])
  103. for i in range(p):
  104. value = get_dot(i, a, b, p)
  105. if (value != False):
  106. x0,y0,x1,y1 = value
  107. xy[x0][y0] = 1
  108. xy[x1][y1] = 1
  109. print('椭圆曲线散点图:')
  110. for i in range(p):
  111. temp = p - 1 -i
  112. if temp >= 10:
  113. print(temp, end='')
  114. else:
  115. print(temp, end='')
  116. # 输出具体坐标值
  117. for j in range(p):
  118. print(xy[j][temp], end='')
  119. print()
  120. print(' ', end='')
  121. for i in range(p):
  122. if i >= 10:
  123. print(i, end='')
  124. else:
  125. print(i, end='')
  126. print()
  127. def get_nG(xG, yG, priv_key, a, p):
  128. """
  129. 计算nG
  130. """
  131. temp_x = xG
  132. temp_y = yG
  133. while priv_key != 1:
  134. temp_x, temp_y = get_PaddQ(temp_x, temp_y, xG, yG, a, p)
  135. priv_key -= 1
  136. return temp_x, temp_y
  137. def get_KEY():
  138. """
  139. 生成公钥私钥
  140. """
  141. # 选择曲线方程
  142. while True:
  143. a = int(input('输入椭圆曲线参数a(a>0)的值:'))
  144. b = int(input('输入椭圆曲线参数b(b>0)的值:'))
  145. p = int(input('输入椭圆曲线参数p(p为素数)的值:'))
  146. # 满足曲线判别式
  147. if (4*(a**3)+27*(b**2))%p == 0:
  148. print('输入的参数有误,请重新输入!\n')
  149. else:
  150. break
  151. # 输出曲线散点图
  152. get_graph(a, b, p)
  153. # 选择基点G
  154. print('在上图坐标系中选择基点G的坐标')
  155. xG = int(input('横坐标xG:'))
  156. yG = int(input('纵坐标yG:'))
  157. # 获取曲线的阶
  158. n = get_order(xG, yG, a, b, p)
  159. # 生成私钥key,且key<n
  160. priv_key = int(input('输入私钥key(<%d):'%n))
  161. #生成公钥KEY
  162. xK, yK = get_nG(xG, yG, priv_key, a, p)
  163. return xK, yK, priv_key, a, b, p, n, xG, yG
  164. def encrypt(xG, yG, xK, yK,priv_key, a, p, n):
  165. """
  166. 加密
  167. """
  168. k = int(input('输入一个整数k(<%d)用于计算kG和kQ:' % n))
  169. kGx, kGy = get_nG(xG, yG, priv_key, a, p) # kG
  170. kQx, kQy = get_nG(xK, yK, priv_key, a, p) # kQ
  171. plain = input('输入需要加密的字符串:')
  172. plain = plain.strip()
  173. c = []
  174. print('密文为:', end='')
  175. for char in plain:
  176. intchar = ord(char)
  177. cipher = intchar * kQx
  178. c.append([kGx, kGy, cipher])
  179. print('(%d,%d),%d' % (kGx, kGy, cipher), end=' ')
  180. print()
  181. return c
  182. def decrypt(c, priv_key, a, p):
  183. """
  184. 解密
  185. """
  186. for charArr in c:
  187. kQx, kQy = get_nG(charArr[0], charArr[1], priv_key, a, p)
  188. print(chr(charArr[2] // kQx), end='')
  189. print()
  190. if __name__ == '__main__':
  191. xK, yK, priv_key, a, b, p, n, xG, yG = get_KEY()
  192. c = encrypt(xG, yG, xK, yK, priv_key, a, p, n)
  193. decrypt(c, priv_key, a, p)

注:加密函数中,计算密文是通过明文字符的ASCII码乘点kQ的x坐标得到,即incharkQx;而一些加密中是将明文转换为大整数再转换为曲线上的点M(x,y),密文为(C1=kG, C2=(M+kQ)),解密M=C1-priv_keyC2=M+kQ-priv_keykG=M+kpriv_keyG-priv_keykG

总结

本文初步介绍了ECC算法的基本原理和实现步骤,另外,椭圆曲线还应用于密钥交换ECDH、数字签名ECDSA等。一些区块链项目中使用的加密算法也是椭圆曲线,如比特币中的数字签名算法Secp256k1。

由于本人水平有限,文章出现纰漏,还请大佬们斧正。

参考文章

https://www.pediy.com/kssd/pediy06/pediy6014.htm

https://blog.dyboy.cn/websecurity/121.html

https://github.com/amintos/PyECC/tree/master/ecc

原文链接:http://www.cnblogs.com/KRDecad3/p/11523396.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号