经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » Python » 查看文章
椭圆曲线密码学(ECC)加解密,附带python代码 - Lxx-123
来源:cnblogs  作者:Lxx-123  时间:2024/6/3 9:28:53  对本文有异议

想起来很久没写博客了,刚好今天要写实验报告,随便把之前的也完成吧

1.椭圆曲线概念

椭圆曲线在经过化解后,可以用这条式子表达:E:y2=x3+ax+b
其背后的密码学原理,是基于椭圆曲线离散对数问题,比RSA算法更有安全且运算速度更快。

在看上面的式子,我们知道构造一个椭圆曲线,需要a,b两个参数
而在有限域GF(p)上的椭圆曲线,则还需要一个参数p,它的表达式为E:y2≡x3+ax+b(mod p)

椭圆曲线的运算是符合Abel群的

1.0+0=0(0是加法单位元)
2.对所有点P=(x,y)∈E(a,b),有P+0=0+P=P
3.对所有点P=(x,y)∈E(a,b),有P+(-P)=0,点P的逆为(x,-y)
4.两点加法(重要),令P(x1,y1)∈E(a,b),Q(x2,y2)∈E(a,b)
则P+Q=R=(x3,y3)∈E(a,b)
x3=(lada)3-x1-x2
y3=lada(x1-x3)-y1
其中lada分为两种情况
一是P不等于Q,lada=(y2-y1)/(x2-x1)
二是P等于Q(倍点规则),lada=(3(x1)2+a)/2y1
5.对所有点P和Q∈E(a,b),满足加法交换侓,P+Q=Q+P
6.对所有点P和Q∈E(a,b),满足加法结合率,P+(Q+R)=(P+Q)+R
7.乘法,KP相当于K个P相加

2.椭圆曲线加解密

了解完椭圆曲线这些概念就可以进行加解密了

1.user2输入需要加密的明文
2.user2待传输的明文以某种编码方式编码到椭圆曲线上一点M
3.user2秘密选择k进行加密,计算点C1=kP;C2=M+kQ,传给user1
4.user1选定一条椭圆曲线=(a,b,p),公开参数a,b,p,
5.user1选择素阶点P
6.user1选择一个私有密钥d,并生成公开密钥Q=dP
7.user1将得到的密文用d进行解密,M=C2-dC1
原理C2-C1=M+kQ-d(kP)=M+K(dP)-d(kP)=M

再对点M进行解码就可以得到明文。

函数功能:
1.从明文消息中的第一个字符开始,使用基于ASCII字符码的明文嵌入方法映射,直到最后一个字符。从而,将明文消息字符编码为椭圆曲线E点。
参数为p点坐标,以及明文,a,b,p椭圆曲线参数,作为才发现后面竟然有给出代码

点击查看代码
  1. def message_to_point(P_x, P_y, message, a, b, p):
  2. points = []
  3. n = 1
  4. for char in message:
  5. k = ord(char) + 1
  6. print(k)
  7. x, y = tuoyuan_cheng(P_x, P_y, k, a, b, p)
  8. points.append((x, y))
  9. print("{}=>({},{})".format(n, x, y))
  10. n += 1
  11. return points

2.此处应用了拓展欧几里得求逆元,在椭圆曲线加法处用到

点击查看代码
  1. def extend_gcd(a, b):
  2. if b == 0:
  3. return a, 1, 0
  4. else:
  5. g, y, x = extend_gcd(b, a % b)
  6. return g, x, y - (a // b) * x
  7. def niyuan(a, b): # 计算a模b的逆元,
  8. g, x, y = extend_gcd(a, b)
  9. if g != 1:
  10. print("a和b不互素,因此不存在逆元")
  11. return None
  12. else:
  13. return x % b

3.椭圆曲线中的加法,因为除后取模很麻烦,此处就用了逆元的思想
实现了
两点加法,令P(x1,y1)∈E(a,b),Q(x2,y2)∈E(a,b)
则P+Q=R=(x3,y3)∈E(a,b)
x3=(lada)3-x1-x2
y3=lada(x1-x3)-y1

点击查看代码
  1. def tuoyuan_jia(P_x, P_y, Q_x, Q_y, a, b, p): # 椭圆曲线中的加法
  2. if P_x == Q_x and P_y == Q_y:
  3. lada = ((3 * (P_x ** 2) + a) * niyuan(2 * P_y, p)) % p
  4. x3 = (lada ** 2 - P_x - Q_x) % p
  5. y3 = (lada * (P_x - x3) - P_y) % p
  6. return x3, y3
  7. elif P_x != Q_x:
  8. lada = ((Q_y - P_y) * niyuan(Q_x - P_x, p)) % p
  9. x3 = (lada ** 2 - P_x - Q_x) % p
  10. y3 = (lada * (P_x - x3) - P_y) % p
  11. return x3, y3
  12. elif P_x == Q_x and P_y != Q_y:
  13. return 0, 0

4.椭圆曲线中的乘法

乘法,KP相当于K个P相加

点击查看代码
  1. def tuoyuan_cheng(P_x, P_y, k, a, b, p): # 椭圆曲线中的乘法,这里的k为乘于几,乘几那么就相当于几个点相加
  2. k = int(k) # 确保k是整数类型
  3. new_x, new_y = P_x, P_y
  4. for i in range(k - 1):
  5. new_x, new_y = tuoyuan_jia(new_x, new_y, P_x, P_y, a, b, p)
  6. return new_x, new_y

5.计算椭圆曲线的阶

点击查看代码
  1. def cal_jie(P_x, P_y, a, b, p):
  2. fuP_x = P_x
  3. fuP_y = -P_y % p
  4. new_x, new_y = P_x, P_y
  5. n = 1 # 初始化n
  6. while True:
  7. n += 1
  8. new_x, new_y = tuoyuan_jia(new_x, new_y, P_x, P_y, a, b, p)
  9. if new_x == fuP_x and new_y == fuP_y:
  10. return n + 1

6.椭圆曲线加密
实现了k进行加密,计算点C1=kP;C2=M+kQ

点击查看代码
  1. def encode(P_x, P_y, Q_x, Q_y, k, points, a, b, p):
  2. poointsC1 = []
  3. poointsC2 = []
  4. kP_x, kP_y = tuoyuan_cheng(P_x, P_y, k, a, b, p)
  5. poointsC1.append((kP_x, kP_y))
  6. print("计算得密文为")
  7. print("c1")
  8. print(poointsC1)
  9. kQ_x, kQ_y = tuoyuan_cheng(Q_x, Q_y, k, a, b, p)
  10. for point in points:
  11. x = point[0]
  12. y = point[1]
  13. x = int(x)
  14. y = int(y)
  15. newkQ_x, newkQ_y = tuoyuan_jia(kQ_x, kQ_y, x, y, a, b, p)
  16. poointsC2.append((newkQ_x, newkQ_y))
  17. print("c2")
  18. print(poointsC2)
  19. return poointsC1, poointsC2

7.椭圆曲线解密
将得到的密文用d进行解密,M=C2-dC1
原理C2-C1=M+kQ-d(kP)=M+K(dP)-d(kP)=M

点击查看代码
  1. def decode(poointsC1, poointsC2, d, a, b, p):
  2. points = []
  3. C1 = poointsC1[0]
  4. C1_x = C1[0]
  5. C1_y = C1[1]
  6. inv_dC1_x, inv_dC1_y = tuoyuan_cheng(C1_x, C1_y,d,a, b, p)
  7. inv_dC1_y=-inv_dC1_y
  8. for point in poointsC2:
  9. C2_x = point[0]
  10. C2_y = point[1]
  11. #M_x=(C2_x-inv_dC1_x)%p
  12. #M_y=(C2_y-inv_dC1_y)%p
  13. M_x, M_y = tuoyuan_jia(C2_x, C2_y, inv_dC1_x, inv_dC1_y, a, b, p)
  14. points.append((M_x, M_y))
  15. print(points)
  16. return points

8.将点转化成明文
此处我没有运用现代密码学教程的思想
而是想着让点不断地加上逆P,使得每次n+1,等到最后点与P相等时,得到n

点击查看代码
  1. def points_to_message(P_x, P_y,points,a, b, p):
  2. message = ""
  3. for point in points:
  4. x = point[0]
  5. y = point[1]
  6. fuP_x=P_x
  7. fuP_y=-P_y
  8. n=0
  9. while x!=P_x and y!=P_y:
  10. x , y=tuoyuan_jia(x, y, fuP_x, fuP_y, a, b, p)
  11. n+=1
  12. char=chr(n)
  13. message+=char
  14. print("解密后的字符串"+message)
  15. return message

python
代码(附带注销):

  1. import math
  2. import random
  3. def extend_gcd(a, b):
  4. if b == 0:
  5. return a, 1, 0
  6. else:
  7. g, y, x = extend_gcd(b, a % b)
  8. return g, x, y - (a // b) * x
  9. def niyuan(a, b): # 计算a模b的逆元
  10. g, x, y = extend_gcd(a, b)
  11. if g != 1:
  12. print("a和b不互素,因此不存在逆元")
  13. return None
  14. else:
  15. return x % b
  16. def tuoyuan_jia(P_x, P_y, Q_x, Q_y, a, b, p): # 椭圆曲线中的加法
  17. if P_x == Q_x and P_y == Q_y:
  18. lada = ((3 * (P_x ** 2) + a) * niyuan(2 * P_y, p)) % p
  19. x3 = (lada ** 2 - P_x - Q_x) % p
  20. y3 = (lada * (P_x - x3) - P_y) % p
  21. return x3, y3
  22. elif P_x != Q_x:
  23. lada = ((Q_y - P_y) * niyuan(Q_x - P_x, p)) % p
  24. x3 = (lada ** 2 - P_x - Q_x) % p
  25. y3 = (lada * (P_x - x3) - P_y) % p
  26. return x3, y3
  27. elif P_x == Q_x and P_y != Q_y:
  28. return 0, 0
  29. def tuoyuan_cheng(P_x, P_y, k, a, b, p): # 椭圆曲线中的乘法,这里的k为乘于几,乘几那么就相当于几个点相加
  30. k = int(k) # 确保k是整数类型
  31. new_x, new_y = P_x, P_y
  32. for i in range(k - 1):
  33. new_x, new_y = tuoyuan_jia(new_x, new_y, P_x, P_y, a, b, p)
  34. return new_x, new_y
  35. def message_to_point(P_x, P_y, message, a, b, p):
  36. points = []
  37. n = 1
  38. for char in message:
  39. k = ord(char) + 1
  40. print(k)
  41. x, y = tuoyuan_cheng(P_x, P_y, k, a, b, p)
  42. points.append((x, y))
  43. print("{}=>({},{})".format(n, x, y))
  44. n += 1
  45. return points
  46. def points_to_message(P_x, P_y,points,a, b, p):
  47. message = ""
  48. for point in points:
  49. x = point[0]
  50. y = point[1]
  51. fuP_x=P_x
  52. fuP_y=-P_y
  53. n=0
  54. while x!=P_x and y!=P_y:
  55. x , y=tuoyuan_jia(x, y, fuP_x, fuP_y, a, b, p)
  56. n+=1
  57. char=chr(n)
  58. message+=char
  59. print("解密后的字符串"+message)
  60. return message
  61. def cal_jie(P_x, P_y, a, b, p):
  62. fuP_x = P_x
  63. fuP_y = -P_y % p
  64. new_x, new_y = P_x, P_y
  65. n = 1 # 初始化n
  66. while True:
  67. n += 1
  68. new_x, new_y = tuoyuan_jia(new_x, new_y, P_x, P_y, a, b, p)
  69. if new_x == fuP_x and new_y == fuP_y:
  70. return n + 1
  71. def encode(P_x, P_y, Q_x, Q_y, k, points, a, b, p):
  72. poointsC1 = []
  73. poointsC2 = []
  74. kP_x, kP_y = tuoyuan_cheng(P_x, P_y, k, a, b, p)
  75. poointsC1.append((kP_x, kP_y))
  76. print("计算得密文为")
  77. print("c1")
  78. print(poointsC1)
  79. kQ_x, kQ_y = tuoyuan_cheng(Q_x, Q_y, k, a, b, p)
  80. for point in points:
  81. x = point[0]
  82. y = point[1]
  83. x = int(x)
  84. y = int(y)
  85. newkQ_x, newkQ_y = tuoyuan_jia(kQ_x, kQ_y, x, y, a, b, p)
  86. poointsC2.append((newkQ_x, newkQ_y))
  87. print("c2")
  88. print(poointsC2)
  89. return poointsC1, poointsC2
  90. def decode(poointsC1, poointsC2, d, a, b, p):
  91. points = []
  92. C1 = poointsC1[0]
  93. C1_x = C1[0]
  94. C1_y = C1[1]
  95. inv_dC1_x, inv_dC1_y = tuoyuan_cheng(C1_x, C1_y,d,a, b, p)
  96. inv_dC1_y=-inv_dC1_y
  97. for point in poointsC2:
  98. C2_x = point[0]
  99. C2_y = point[1]
  100. #M_x=(C2_x-inv_dC1_x)%p
  101. #M_y=(C2_y-inv_dC1_y)%p
  102. M_x, M_y = tuoyuan_jia(C2_x, C2_y, inv_dC1_x, inv_dC1_y, a, b, p)
  103. points.append((M_x, M_y))
  104. print(points)
  105. return points
  106. def main():
  107. print("****ECC椭圆曲线加解密****")
  108. while True:
  109. a = int(input("请输入椭圆曲线参数a(a>0)的值:"))
  110. b = int(input("请输入椭圆曲线参数b(b>0)的值:"))
  111. p = int(input("请输入椭圆曲线参数p(a>0)的值:"))
  112. if 4 * (a ** 3) - 27 * (b ** 2) % p == 0:
  113. print("输入的参数有误,请重新输入")
  114. else:
  115. break
  116. print("user1:在如上坐标系中选一个素阶点P")
  117. P_x = int(input("请输入选取的x坐标值:"))
  118. P_y = int(input("请输入选取的y坐标值:"))
  119. n = cal_jie(P_x, P_y, a, b, p)
  120. d = int(input(("user1:请输入用于生成公钥的私钥d(<{}):".format(n))))
  121. Q_x, Q_y = tuoyuan_cheng(P_x, P_y, d, a, b, p)
  122. print(" 计算Q=d*P得公钥Q为(" + str(Q_x) + "," + str(Q_y) + ")")
  123. mingwen = input("user2:请输入需要加密的字符串:")
  124. mingwen = mingwen.strip() # 通过strip()方法可以去除字符串两端的空格
  125. print("明文映射的点为:")
  126. points1 = message_to_point(P_x, P_y, mingwen, a, b, p)
  127. k = input("user2:请输入秘密选择的k(<{}):".format(n)) # 这一步我们不用,我们选择用随机数
  128. # k = random.randint(1, n) # 生成1到阶n之间的随机整数,用于计算kP,kQ
  129. print("user2:计算得密文为")
  130. poointsC1, poointsC2 = encode(P_x, P_y, Q_x, Q_y, k, points1, a, b, p)
  131. print("user1解密得到明文映射的点为:")
  132. points2=decode(poointsC1, poointsC2, d, a, b, p)
  133. points_to_message(P_x, P_y,points2,a, b, p)
  134. if __name__ == "__main__": # 函数入口
  135. main()

3.原始输入输出

欢迎指正

原文链接:https://www.cnblogs.com/l-xx123/p/18227104

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

本站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号