文章最后更新时间为:2018年12月26日 23:07:29

RSA是一种公钥密码算法,其影响力我就不多说了,算法原理网上多的是,看了几篇,还是觉得阮一峰写的好懂。

要想实现RSA,其关键在于大数运算,无论是大数之间的加减乘除还是模幂运算,都是普通的数据结构无法完成的,如果你是使用C语言来实现,那么你还需要首先解决五百位数字的加减乘除问题。

但是python语言有个好处,就是自动实现大数运算,其数据结构是不限制位数的。比如>>> x = 99999999999999999999999999999999999999999999999999

>>> x += 1

>>> x

100000000000000000000000000000000000000000000000000

>>> print(999**999)

36806348825922326789470084006052186583833823203735320465595962143702560930047223153010387361450517521869134525758989639113039318944796977164583238219236607653663113200177617597793217865870366077846576581183082787698201412402294867197567813172495806442794

但是如果用C语言就需要自己造轮子,手动构造函数实现大数运算。

没有大数运算的麻烦,实现RSA就简单的多了。现在思考一下,我们还有两个问题。怎么产生一个大素数

怎么实现大数的模幂运算

接下来我们就来一一解决这两个问题。

1.实现大数的模幂运算

为什么先解决这个呢,因为大素数的产生需要用到这个函数,所以我们首先实现大数的模幂运算。

先来考虑一个简单的问题,怎么计算 3 ^ 13 (mod 9)?

那还用想?直接用计算机算 3 ^ 13 不就好了,但是如果是33333 ^ 1333333333呢,这计算机得算到什么时候,所以我们得想个法子减少计算量。

这里要利用到我们所熟知的两个公式

(a * b) (mod n) = a (mod n) * b (mod n)

a ^ (b+c) = a^b * a^c

那么上面的13 = 1*2^3 + 1*2^2 + 0*2^1 + 1*2^0。3^13就可以转化为3^(1*2^3) * 3^(1*2^2) * 3^(0*2^1) * 3^(1*2^0)

到这里我们就清楚了。我们可以先算3^(1*2^0) (mod 9),假设其结果为res。然后再算3^(0*2^1) (mod 9), 那么这个就等于0 * res^2 (mod 9),所以我们只要将上一步的数值乘以该二进制数的系数再平方。一直类推下去, 然后把每一步得到的结果res乘起来模上9,就是 3^(1*2^3) * 3^(1*2^2) * 3^(0*2^1) * 3^(1*2^0) (mod 9)

对于所有的a^b (mod n)都可以这么做,把b分解为二进制。这种快速模幂运算也叫蒙哥马利运算。

看代码来理解更方便:def pow_mod(p, q, n):

'''

幂模运算,快速计算(p^q) mod (n)

这里采用了蒙哥马利算法

'''

res = 1

while q :

if q & 1: # 如果q & 1=1,那么其二进制形式的最后一位等于1

res = (res * p) % n

q >>= 1 # 每一轮右移一位,就能得出其二进制每位是0还是1

p = (p * p) % n

return res

2.产生一个大素数

我们解决的思路是先产生一个大数,然后再判断其是不是素数。

产生大数很简单,直接使用rand函数来产生每一位数字,然后拼接起来不就好了吗。

直接看代码即可def probin(w):

'''

随机产生一个伪素数,产生 w表示希望产生位数

'''

list = []

list.append('1') #最高位定为1

for i in range(w - 2):

c = random.choice(['0', '1'])

list.append(c)

list.append('1') # 最低位定为1

res = int(''.join(list),2)

return res

通过以上代码我们产生了一个非常大的奇数,但是我们怎么来检验其是否为素数呢,这里使用了非常通用的miller rabin算法来检验。

其算法原理是利用了费马定理的结论:费马小定理:对于素数p和任意整数a,有a^(p−1) = 1 (mod p)

Miller Rabin素数判定,在费马定理的基础上增加了二次判定:如果p是素数,则 x^2=1 (mod p)的解为x=1或x=p−1(mod p)

根据费马定理,如果p为素数,正好有 a^(p−1) = 1 (mod p),那么x^((p-1)/2) = 1 或者 p-1。如果x^((p-1)/2) = 1,那么x^((p-1)/2/2) = 1 或者p-1.....

直到(p-1)/2/2/2/2...不能再继续除2了为止(再除2就会产生小数,这里我们所有的数字都得是整数。)

因为a^(p−1) = 1 (mod p)是必然存在的,那么必然会有一个解。如果直到算到(p-1)除2除不了了也没有结果,那么p就不是素数。

对于任意两个素数都需要符合费马定理,且满足二次定理,即对于任意的a, a^(p−1) = 1 (mod p)有解。

那么满足上述两个条件是否一定证明其为素数,也不是,这只是一个必要但不充分条件,但是科学证明,当取任意多个a都符合上述条件的时候,我们就可以判断其为素数(误判的概率很小)。

接下来我们就来判断一个大数是否满足费马定理和二次定理。def prime_miller_rabin(a, n): # 随机生成a, 检测n是否为素数

'''

第一步,模100以内的素数,初步排除很显然的合数

'''

Sushubiao=(2,3,5,7,11,13,17,19,23,29,31,37,41

,43,47,53,59,61,67,71,73,79,83,89,97)# 100以内的素数

for y in Sushubiao:

if n % y==0:

return False

'''

第二步 用miller rabin算法对n进行检测

'''

if pow_mod(a, n-1, n) == 1: # 费马定理,如果a^(n-1)!= 1 mod n, 说明为合数

d = n-1 # n-1 = (2^q )* m, 求q和m的值,用来判断二次定理

q = 0

while not(d & 1):

q = q+1

d >>= 1

m = d

for i in range(q): # 0~q-1, 我们先找到的最小的a^u,再逐步扩大到a^((n-1)/2)

u = m * (2**i)

tmp = pow_mod(a, u, n)

if tmp == 1 or tmp == n-1: # 如果满足,则a^(n−1) = 1 (mod n)有解。

# 满足条件

return True

return False

else:

return False

接下来我们随机产生几个a,来检验其是否都满足费马定理和二次定理。def prime_test(n, k): # 产生k个a

while k > 0:

a = random.randint(2, n-1)

if not prime_miller_rabin(a, n): # 如果返回false,说明这不是个素数,不用继续测试了

return False

k = k - 1

return True

然后就到了产生素数的函数了。这里我们使用while循环,什么时候产生素数成功了什么时候退出。def get_prime(bit):

while True:

prime_number = probin(bit) # 产生bit位的素数

for i in range(50): # 伪素数附近50个奇数都没有真素数的话,重新再产生一个伪素数

u = prime_test(prime_number, 8) # 检验8个a来判断产生的是不是素数

if u:

break

else:

prime_number = prime_number + 2*(i)

if u:

return prime_number

else:

continue

上述代码很直观,直接产生一个大奇数来判断,如果不是素数,则把大素数加2再进行判断。依次类推,加上50次以后还不是素数的化则重新生成一个大奇数。

遍历 [奇数, 奇数+100]的范围应该会有一个素数,这样也提高了成功率。

今天上课听老师说还有一种方法来避免盲目的产生大数,设产生大数为A, 如果A对7取模是5,那么A+5、A+12、A+19、A+26都是7的倍数,也就不是素数了,这样就可以排除这些数字。同样的方法对100以内的数字取模,然后排除掉A后的很多数字,下一次就可以直接取没有被排除的数字。这样就需要生成一个数组来保存被排除的数。

其实思路差不多,我的代码是直接加2,实现起来简单一点,如果不需要产生很多很多的大素数,效果应该也不差。

接下来就是RSA了,我们还得取一个e,这里的e是加密用的,如果实现了模幂运算,那么你就会明白e的取值直接影响了加密的速度,一般e的取值都是比较小,几位或者十几位二进制,而且二进制里的1要少(加快模幂运算速度,思考一下为什么)。

e还需要和(p-1)*(q-1)互素,因为要求模幂,这里我们暂定其为65537(二进制为10000000000000001)。如果和(p-1)*(q-1)不互素,那我们就换一个。所以这里还要有个函数来检测e和(p-1)*(q-1)是否互素。def gcd(a,b):

'''

欧几里得算法求最大公约数

'''

while a!=0:

a, b =b%a , a

return b

代码很简单,利用了欧几里得算法求公约数,公约数为1不就互素了吗。

到现在我们已经确定e和p,q,加密看起来so easy了。

但是解密还要求出解密密钥 d = e ^(-1) (mod (p-1)*(q-1))。这里也就是求e对于(p-1)*(q-1)的逆。

我的天还要实现模逆运算,这里直接网上找了一个,写文章的时候忘记在那里抄的了,对作者说声抱歉!def mod_1(x, n):

'''

扩展欧几里得算法求模逆

取模负1的算法:计算x2= x^-1 (mod n)的值

'''

x0 = x

y0 = n

x1 = 0

y1 = 1

x2 = 1

y2 = 0

while n != 0:

q = x // n

(x, n) = (n, x % n)

(x1, x2) = ((x2 - (q * x1)), x1)

(y1, y2) = ((y2 - (q * y1)), y1)

if x2 < 0:

x2 += y0

if y2 < 0:

y2 += x0

return x2

解密密钥d也算出来了,事情到这里好像就结束了。是的,真的结束了。

好像少了点什么?对,有图才有真相!

完。

python语言实现rsa公钥密码算法_python实现RSA算法相关推荐

  1. python实现rsa加密源代码_python实现RSA加密(解密)算法

    RSA是目前最有影响力的公钥加密算法,它能够抵抗到目前为止已知的绝大多数密码攻击,已被ISO推荐为公钥数据加密标准. 今天只有短的RSA钥匙才可能被强力方式解破.到2008年为止,世界上还没有任何可靠 ...

  2. python语言特点依赖平台吗_python语言的特点

    Python既支持面向过程编程,也支持面向对象编程.在"面向过程"的语言中,程序是由过程或仅仅是可重用代码的函数构建起来的.在"面向对象"的语言中,程序是由数据 ...

  3. python语言程序设计及医学应用_Python语言程序设计(高等学校计算机专业规划教材)...

    第1章Python语言概述/1 1.1Python语言的发展1 1.1.1Python的起源1 1.1.2Python的发展2 1.2Python语言的特点2 1.2.1Python的特性2 1.2. ...

  4. python扫雷 高级算法_Python玩转算法—扫雷

    此题来自LeetCode上的一道难度为Medium的题,说是有一张玩到一半的扫雷地图,接下来给你指定一个点击位置,让你预测点击之后,地图将发生怎么样的变化.看到这道题,瞬间让我想起了以前玩扫雷的日子, ...

  5. python语言程序设计刘卫国答案_Python语言程序设计

    章Python语言基础1 1.1Python语言概述1 1.1.1Python语言的发展历史1 1.1.2Python语言的特点2 1.1.3Python语言的应用领域3 1.2Python语言的开发 ...

  6. python语言的数据类型有哪些_Python语言有哪些数据类型

    在Python中,能够直接处理的数据类型有以下几种: 一.整数 Python可以处理任意大小的整数,当然包括负整数,在Python程序中,整数的表示方法和数学上的写法一模一样,例如:1,100,-80 ...

  7. python语言的主要网站是_python语言主要是做什么的

    python是一款应用非常广泛的脚本程序语言,谷歌公司的网页就是用python编写.python在生物信息.统计.网页制作.计算等多个领域都体现出了强大的功能.python和其他脚本语言如java.R ...

  8. python语言句块的标记_Python语言语句块的标记是()

    [简答题] [单选题]Listen( 1.1-1) and answer: Karen Wood is ___________. [单选题]下列说法正确的是 ( ). [判断题]旅游的实质实人类追求自 ...

  9. python语言编程中的保留字_Python语言程序设计整理

    第一周:Python基本语法元素 1.3 实例1:温度转换 例:将摄氏度和华氏度互换 利用转换公式如下: C=(F-32)/1.8,F=C*1.8+32 代码: 1.4Python程序语法元素分析 1 ...

最新文章

  1. Java并发 -- JMM
  2. 去耦电容和旁路电容详解
  3. Hadoop生成HFile直接入库HBase心得
  4. Node.js中模块加载机制
  5. ElasticSearch服务器操作命令
  6. 牛客多校2 - Cover the Tree(dfs序)
  7. WebService之Axis2快速入门(2): 传递复合类型的数据
  8. 直流有刷电机与无刷电机的区别
  9. RSA2048 public key der格式结构
  10. Deep Learning学习笔记(5)——AlphaGo
  11. 锐龙调用python库的问题_一个小白对当前锐龙4000笔记本的愚见
  12. 零基础想学大数据?你需要这个完整学习路线
  13. ubuntu16.04 鼠标右键没有压缩/解压 选项
  14. 潘金莲给武松的最后一封信
  15. 作图,用ECharts就够了
  16. ShopXO开源电商系统源码支持PC+H5支付宝小程序微信小程序百度小程序头条amp;抖音小程序QQ小程序APP等
  17. ESP8266-AP模式作服务器
  18. 半同态加密paillier 示例
  19. 简述使用混合传递参数时的基本原则_东南大学传热学考试真题试卷与解析
  20. 迄今为止最全的前端监控体系搭建篇(长文预警)

热门文章

  1. 【论文精度】Youtube团队打造深度神经网络与推荐算法结合开山之作Deep Neural Network for YouTube Recommendation
  2. STM32----IIC详解
  3. 风格迁移论文----关于内容结构的控制
  4. 【MySql笔记】1.0
  5. kruskal算法c语言,最小生成树之Kruskal算法
  6. 使用Autoware标定工具包联合标定相机和激光雷达
  7. Restful风格的请求
  8. 哪款电脑监控软件适合公司使用(电脑监控软件哪个好?)
  9. word文档将单词表中单词挖空
  10. 日常生活如何快速学习