RSA加密算法

前言

公钥加密算法(RSA)是首个适用以签名作为加密的算法。被用于银行网上支付、电商交易。
RSA是Rivest、Shamir、Adleman三位数学家的缩写。其数学原理是大整数因数分解极其苦难的原因设计的一种算法。

蒙哥马利幂运算

蒙哥马利幂运算是为了快速计算 a b m o d ( c ) a^bmod(c) abmod(c)的一种算法,是RSA加密算法核心之一,用于求私钥值 d ( d = a b m o d ( c ) ) d(d=a^b mod (c)) d(d=abmod(c)),其中mod求余符号等价于python里面的%符号。
a b m o d ( c ) a^bmod(c) abmod(c)
当其中a为大整数时,直接求 a b a^b ab会导致内存溢出,若采用其他算法。
举个例子来说:
a循环相乘,则计算速度太慢
这样情况下,有人提出了如下公式:
m ∗ x m o d ( n ) = ( m m o d ( n ) ) ∗ ( x ∗ m o d ( n ) ) ∗ m o d ( n ) m*x mod(n)=(m mod(n))*(x*mod(n))*mod(n) mxmod(n)=(mmod(n))(xmod(n))mod(n)
其中 m , x m,x m,x两个数的积与 n n n求余,可以才拆分成每个数与 n n n求余相乘再与 n n n求余。由此可以把指数 a b a^b ab分解成 a 1 , a 2 ⋅ ⋅ ⋅ , a y a^1,a^2···,a^y a1,a2,ay相乘,其中 1 + 2 + 3 + ⋅ ⋅ ⋅ + y 1+2+3+···+y 1+2+3++y y = b 2 y=\frac{b}{2} y=2b取整数时获取。
其中当 b b b为奇数时,分解的结果为 a 2 y + 1 a^{2y+1} a2y+1
其中当 b b b为偶数时,分解的结果为 a 2 y a^{2y} a2y
举个例子:
2 × 3 m o d ( 5 ) = ( 2 m o d ( 5 ) ) × ( 3 m o d ( 5 ) ) m o d ( 5 ) = 1 2×3 mod(5)=(2 mod(5))×(3mod(5))mod(5)=1 2×3mod(5)=(2mod(5))×(3mod(5))mod(5)=1
6 % 5 余 1 6\%5 余1 6%51

def Montgomery(a,b,c):
    if b==1:
        print('余数是%d,底数是%d,指数是%d'%(a%c,a,b)) # a^bmod(c)
        return a%c

    r = Montgomery(a,b>>1,c)%c

    if b%2==0: # 为偶数时
        print('余数是%d,底数是%d,指数是%d'%((r*r)%c,a,b))
        return (r*r)%c
    else: # 为基数数
        print('余数是%d,底数是%d,指数是%d'%(a*(r*r)%c,a,b))
        return (a*(r*r)%c)

a = 2 # 底数
b = 9 # 指数
c = 10 # 模右边数
result = Montgomery(a,b,c) # 调用递归函数
print('最后求得的幂模数为:%d'%(result))
余数是2,底数是2,指数是1
余数是4,底数是2,指数是2
余数是6,底数是2,指数是4
余数是2,底数是2,指数是9
最后求得的幂模数为:2

其实在python环境下:一行搞定
a**b%c
2**9%10=2

1.RSA算法原理

大整数的因数分解是非常困难的,目前是大批量的暴力计算。
移植目前最长的RSA密钥是768个二进制位,所以在1024bit以上基本安全,2048bit以上极其安全。
在这里插入图片描述

1.1RSA的计算过程

参考:https://www.pianshen.com/article/3847777488/

上述过程中,出现了公钥(3233,17)和私钥(3233,2753),这两组数字是怎么找出来的呢?参考RSA算法原理(二)
首字母缩写说明:E是加密(Encryption)D是解密(Decryption)N是数字(Number)。

1.随机选择两个不相等的质数p和q。
alice选择了61和53。(实际应用中,这两个质数越大,就越难**。)

2.计算p和q的乘积n。
n = 61×53 = 3233
n的长度就是长度。3233写成二进制是110010100001,一共有12位,所以这个就是12位。实际应用中,RSA**一般是1024位,重要场合则为2048位。

3.计算n的欧拉函数φ(n)。称作L
根据公式φ(n) = (p-1)(q-1)
alice算出φ(3233)等于60×52,即3120。

4.随机选择一个整数e,也就是公钥当中用来加密的那个数字
条件是1< e < φ(n),且e与φ(n) 互质。
alice就在1到3120之间,随机选择了17。(实际应用中,常常选择65537。)

5.计算e对于φ(n)的模反元素d。也就是**当中用来解密的那个数字
所谓"模反元素"就是指有一个整数d,可以使得ed被φ(n)除的余数为1。ed ≡ 1 (mod φ(n))
alice找到了2753,即17*2753 mode 3120 = 1

6.将n和e封装成公钥,n和d封装成私钥。
在alice的例子中,n=3233,e=17,d=2753,所以公钥就是 (3233,17),私钥就是(3233, 2753)。

上述故事中,blob为了偷偷地传输移动位数6,使用了公钥做加密,即6^17 mode 3233 = 824。alice收到824之后,进行解密,即824^2753 mod 3233 = 6。也就是说,alice成功收到了blob使用的移动位数。

再来复习一下整个流程:
p=17,q=19
n = 1719 = 323
L = 1618 = 144
E = 5(E需要满足以下两个条件:1<E<144,E和144互质)
D = 29(D要满足两个条件,1<D<144,D mode 144 = 1)
假设某个需要传递123,则加密后:123^5 mode 323 = 225
接收者收到225后,进行解密,225^ 29 mode 323 = 123

基于python的RSA算法实现

def Montgomery(a,b,c):
    if b==1:
        print('余数是%d,底数是%d,指数是%d'%(a%c,a,b)) # a^bmod(c)
        return a%c

    r = Montgomery(a,b>>1,c)%c

    if b%2==0: # 为偶数时
        print('余数是%d,底数是%d,指数是%d'%((r*r)%c,a,b))
        return (r*r)%c
    else: # 为基数数
        print('余数是%d,底数是%d,指数是%d'%(a*(r*r)%c,a,b))
        return (a*(r*r)%c)

# a = 2 # 底数
# b = 9 # 指数
# c = 10 # 模右边数
# result = Montgomery(a,b,c) # 调用递归函数
# print('最后求得的幂模数为:%d'%(result))

def gcd(a,b):
    if a%b==0: # 用欧几里得递归求两个正整数的最大公约数
        return b # 当余数为0时,找到最大公约数
    c = gcd(b,a%b)
    return c # 返回最大公约数

def e_gcd(a,b):
    if b==0:
        return 1,0,a
    else:
        x,y,q = e_gcd(b,a%b)
        x,y = y,(x-(a//b)*y)
        return x,y,q

def Keys(p,q,e): # 计算n、e、d
    if gcd(p,q)==1:
        n = p*q
    else:
        print('p=%d,q=%d不是互质的!,算法停止'%(p,q))
        return 0,0,0
    fn = (p-1)*(q-1)
    x,y,q=e_gcd(e,fn)
    if x<0:
        x = (x+fn)%fn
    d = x
    return n,e,d

def Econde(m,e,n): # 对明文进行加密
    c = Montgomery(m,e,n) # 调用蒙哥马利幂运算
    return c # 返回密文c
def Decode(c,d,n):# 对密文进行解密
    m = Montgomery(c,d,n) # 调用蒙哥马利幂运算
    return m

if __name__ == '__main__':
    p,q,e = 2333,150,3111 # 求得公钥(n,e),求私钥(d,e)
    n,e,d = Keys(p,q,e)
    print('n=%d,e=%d,d=%d'%(n,e,d))
    m = 151 # 要发送的信息
    if n!=0 and e!=0:
        c = Econde(m,e,n)
        print('明文%d的密文是:\n%d'%(m,c))
        m1=Decode(c,d,n)
        print('密文解密结果是:',m1)
n=349950,e=3111,d=177699
余数是151,底数是151,指数是1
余数是293401,底数是151,指数是3
余数是296251,底数是151,指数是6
余数是344551,底数是151,指数是12
余数是103351,底数是151,指数是24
余数是255301,底数是151,指数是48
余数是87151,底数是151,指数是97
余数是331951,底数是151,指数是194
余数是260251,底数是151,指数是388
余数是237301,底数是151,指数是777
余数是103501,底数是151,指数是1555
余数是123151,底数是151,指数是3111
明文151的密文是:
123151
余数是123151,底数是123151,指数是1
余数是35701,底数是123151,指数是2
余数是157051,底数是123151,指数是5
余数是190651,底数是123151,指数是10
余数是274651,底数是123151,指数是21
余数是318601,底数是123151,指数是43
余数是100201,底数是123151,指数是86
余数是160501,底数是123151,指数是173
余数是322651,底数是123151,指数是347
余数是191851,底数是123151,指数是694
余数是115051,底数是123151,指数是1388
余数是223801,底数是123151,指数是2776
余数是64951,底数是123151,指数是5553
余数是335101,底数是123151,指数是11106
余数是24301,底数是123151,指数是22212
余数是172951,底数是123151,指数是44424
余数是237301,底数是123151,指数是88849
余数是151,底数是123151,指数是177699
密文解密结果是: 151
  • 2
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wency(王斯-CUEB)

我不是要饭的

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值