(加密基础)RSA篇

RSA算法

RSA是一种非对称加密算法,假如甲要和乙通讯,甲使用公钥 A 加密,将密文传递给乙,乙使用私钥 B 解密得到明文,其中公钥是在网络上进行传递的,私钥只有乙自己拥有,不在网络上传递,这样即使知道了公钥 A 也无法解密传输的信息

RSA算法原理和python代码实现

1.生成公私钥

1.1给定两个质数P,Q

这里的P,Q越大,该算法就会越安全,为了方便描述,这里给定P=67,Q=71,那么他们的乘积n=4757

1.2计算n的欧拉函数φ(n)

根据欧拉函数的定义,φ(n)等于所有小于等于n的正整数中与n互质的个数,又因为P*Q=n,且PQ均为素数,所以φ(n) =(P-1)(Q-1)= 66 * 70 = 4620

1.3随机选择一个整数e(1<e<m) and e与m互质

这里随机选取e=101,注意,当e=m时会导致公私钥相同

1.4给定整数d,使得(e*d)%m=1
因为 (e*d)%m=1  

所以 e*d-m*y=1(y为整数),由上述可知 e = 101,m = 4620 

所以 101d-4620y=1

根据相关定理(d,y)=1=101d-4620y

根据扩展欧几里得算法:

4620=101x4+75
101=75x1+26
75=26x2+23
23=3x7+1
3=2x1+1
---->
101x1601-35x4620

得到d等于1601

计算完成后,得到公钥 (n,e)=(4757,101) ,私钥 (n,d)=(4757,1601),根据RSA算法的效果,除了接收方自己,没有人知到私钥,那么通过公钥能否得到私钥呢

已知(e*d)%m=1,已知n,e,那么要求d只需要求出n

而我们知道m是n的欧拉函数φ(n),想要知道m就必须将n分解成两个质数的乘积
这里由于数比较小,我们很容易分解出PQ的值,而随着n的增大,分解会变得异常困难

2.加密生成密文

假设需要加密的数字时a
那么将a转化成int就是97
计算过程如下:

97^101%4757=3589

在这里插入图片描述

3.解密密文

根据公式
a^d % n = b

就可以得出明文

在这里插入图片描述

python代码实现

由于C语言不支持大数,所以使用C语言实现异常麻烦这里采用python代码


# -*- coding: cp936 -*-


def isPrime(number):
    import math
    i = 2
    sqrtnum = (int)(math.sqrt(number))
    for i in range(2, sqrtnum + 1):
        if number % i == 0:
            return False
        i = i + 1
    return True


def is_ET_Prime(ee, tt):
    while tt != 0:
        a = ee
        ee = tt
        tt = a % tt
    if ee == 1:
        return True
    else:
        return False


def get_publickey(k, t):
    d = 0
    while ((d * k) % t != 1):
        d += 1
    return d


def encryption(plain, d, n):
    re = (plain ** d) % n

    return re


if __name__ == "__main__":
    print
    "~" * 70
    Flag = False
    while True:
        p = int(input("please input a prime p:"))
        q = int(input("please input a prime q:"))

        if (isPrime(p) and isPrime(q)):
            break
        else:
            print
            "p or q is not prime!"
            continue

    print
    "p=", p, "q=", q

    n = q * p
    t = (q - 1) * (p - 1)
    print("n=", n, "t=", t)

    print("~" * 70)

    Flag == False
    while Flag == False:
        e = int(input("please input a private key:"))
        Flag = is_ET_Prime(e, t)
        if Flag == False:
            print("e is not prime with the t!")

    print("the private key e=", e)

    d = get_publickey(e, t)
    print("the public key d=", d)

    plain = int(ord(input("please input the plain you want to entrypted:")))

    encry = encryption(plain, d, n)
    print("plain", plain, "is encrypted as", encry)
    #print(encry)
    plain1 = encryption(encry, e, n)
    print("encrypt", encry, "is decrypted as", plain1)

RSA共模攻击

假设有一条信息m,由两个不同的用户使用公钥进行加密(两个用户的e一般不同,模数n一般相同)

c1 = m^e1 mod n
c2 = m^e2 mod n

得到了两个不同的密文c1,c2

共模攻击这得到了这两个密文c1,c2,因为公钥是公开的(e1,e2,n)已知

那么攻击者一共知道如下信息

gcd(e1, e2) = 1
m = c1^d1 mod n
m = c2^d2 mod n

那么根据上述就可以直接求出明文m,由于gcd(e1,e2)那么存在整数s1,s2使得e1*s1+e2*s2=1,又因为

c1=m^e1 mod n
c2=m^e2 mod n

所以:

c1^s1 mod n=m^(e1*s1) mod n
c2^s2 mod n=m^(e2*s2) mod n
c1^s1*c2^s2 mod n=m^(e1*s1+e2*s2) mod n
又因为e1*s1+e2*s2=1
所以
c1^s1*c2^s2  =m mod n
再由扩展欧几里得算法和e1*s1+e2*s2=1,即可求出s1,s2

代码模板:

from libnum import n2s,s2n
from gmpy2 import invert

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

def main():
    n = int(input("请输入一个十六进制数n"),16)
    c1 = int(input("请输入一个十六进制数c1"),16)
    c2 = int(input("请输入一个十六进制数c2"),16)
    e1 = int(input("请输入一个十六进制数e1"),16)
    e2 = int(input("请输入一个十六进制数e2"),16)
    s = egcd(e1, e2)
    s1 = s[1]
    s2 = s[2]
    # 求模反元素
    if s1<0:
        s1 = - s1
        c1 = invert(c1, n)
    elif s2<0:
        s2 = - s2
        c2 = invert(c2, n)

    m = pow(c1,s1,n)*pow(c2,s2,n) % n
    print n2s(m)

if __name__ == '__main__':
  main()

猜你喜欢

转载自blog.csdn.net/weixin_43632667/article/details/106415454
今日推荐