python RSA加解密实验

不足 90行代码,只引入了 random 这一个模块,运行速度5秒以内。写了详细的注释。
复杂的只有两个算法

  • 欧几里得算法:代码来自维基百科
  • 素性检测算法:其中可以设置检测次数k
import random

def is_prime(num):
    "判断是否为素数,10次素性检测"
    if num < 2:return False
    small_primes = [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, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997]
    if num in small_primes: return True     # 如果是小素数,那么直接返回true
    # 如果大数是这些小素数的倍数,那么就是合数,返回false
    for prime in small_primes:
        if num % prime == 0:return False
    # 用miller_rabin算法对n进行10次检测(错误概率(1/4)^k)
    d = num - 1
    r = 0
    while d % 2 == 0:
        d = d // 2
        r += 1
    for _ in range(10):
        a = random.randint(2,num-1)  # 随机数
        x = pow(a, d, num)
        if x == 1 or x == num - 1:continue
        for _ in range(r - 1):x = pow(x, 2, num)
        if x == 1:return False
        if x == num - 1:break
    else:return False
    return True

def get_prime(key_size=512):
    # 生成一个素数
    while True:
        num = random.randrange(2**(key_size-1), 2**key_size)
        if is_prime(num):return num

def ext_euclid(a, b):
    "扩展欧几里得算法 返回(x,y 最大公约数): 给定二个整数a、b,必存在整数x、y使得ax + by = gcd(a,b)"
    old_s,s=1,0
    old_t,t=0,1
    old_r,r=a,b
    if b == 0:
        return 1, 0, a
    else:
        while(r!=0):
            q=old_r//r
            old_r,r=r,old_r-q*r
            old_s,s=s,old_s-q*s
            old_t,t=t,old_t-q*t
        while(old_s<0):old_s+=b
    return old_s, old_r

if __name__ == "__main__":
    # 第一步,随机选择两个不相等的质数p和q
    while True:
        choice = input("1、手动输入两个素数\n2、随机生成两个大素数\n请选择:")
        if choice=='1':
            p = int(input("素数1:"))
            q = int(input("素数2:"))
        else:
            p,q = get_prime(),get_prime()
        if is_prime(p) and is_prime(q): break
        else:print("检测到非质数,重新输入!")
    print("生成的大质数为:\n%d\n%d"%(p,q))
    # 第二步,计算p和q的乘积n
    n=p*q
    length=len(bin(n))-2
    # 第三步,计算n的欧拉函数φ(n)
    e = eular=(p-1)*(q-1)
    print("n的欧拉函数φ(n) = %d"%eular)
    # 第四步,随机选择一个整数e,条件是1< e < φ(n),且e与φ(n) 互质
    while eular%e==0:
        e = get_prime(key_size=random.randint(1, length))
    print("选择的整数e = %d"%e)
    # 第五步,计算e对于φ(n)的模反元素d
    d, temp = ext_euclid(a=e,b=eular) # ed ≡ 1(mod eular)
    assert temp == 1
    print("模反元素d = %d"%d)
    # 第六步,将n和e封装成公钥,n和d封装成私钥
    print("公钥(n,e)=(%d,%d)"%(n, e))
    print("私钥(n,d)=(%d,%d)"%(n, d))
    # 第七步,实现加密
    print("当前N长度为 %s 位,最长加密长度 %d 字节"%(length,length//8))
    plaintext = list(input("请输入要加密的内容:\n").encode())
    plaintext_int=int("".join(["{:08b}".format(x) for x in plaintext]),2)
    ciphertext = pow(plaintext_int, e, n)
    print("密文是:\n",ciphertext)
    # 第八步,实现解密
    cliphertext_bin = bin(pow(ciphertext, d, n))[2:]
    if len(cliphertext_bin)%8!=0:cliphertext_bin = '0' * (8 - len(cliphertext_bin) % 8) + cliphertext_bin           # 补0
    plaintext = bytes([int(cliphertext_bin[i * 8:(i + 1) * 8], 2) for i in range(len(cliphertext_bin) // 8)]).decode()  # 转码
    print("解密后的内容是:\n", plaintext)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值