现代密码学-Cryptography 实验三
摘要
本次实验涉及RSA算法,包括RSA加解密以及公钥密钥产生的过程。
T1
题目
RSA加密基于以下流程:
生成两个不同的素数p和q。计算n=pq以及φ=(p-1)(q-1)。
找到整数e,满足1<e<φ,且gcd(e,φ)=1。
RSA系统能加密的信息是区间[0,n-1]中的整数。
因此,需要加密的文本首先需要转换成可加密的信息(即区间[0,n-1]内的某个整数)。
加密文本时,如果文本转换成的信息是m,则加密为\(c=m^{e}\mod n\)。
解密文本时,需要以下流程:计算d满足ed=1 mod φ,如果加密的信息是c,则解密为\(m=c^{d}\mod n\)。
存在某些e和m使得\(m^{e}\mod n=m\)。
我们称满足\(m^{e}\mod n=m\)的这些m为未加密信息。
在选择e时,很重要的一点就是不应该有太多未加密信息。
例如,令p=19,q=37。
然后\(n=19\times 37=703\),\(φ=18\times 36=648\)。
如果我们选择e=181,那么尽管gcd(181,648)=1,但是所有可能的信息
m (0≤m≤n-1)都是未加密信息,只要我们计算一下\(m^{e}\mod n\)就能发现。
对于任意的e,总是存在一些未加密信息。
使得未加密信息的数目为最小值是很重要的。
现在我们选择p=1009,q=3643。
找出所有e,满足1<e<φ(1009,3643)且gcd(e,φ)=1,并且此时未加密信息的数目为最小值。求出所有这些e的和。
思路
这道题的关键点集中于下面这条式子:
由于暴力枚举e和m会花费无法接受的时间,因此我在数学上做了非常多的尝试,然而凭我自己并没有推导出合适的结果,因此我查阅了许多资料,其中
关于“RSA不动点”的讨论和欧拉计划182解决方案这两篇文章都提到了一个共同的结论,即对于
这条式子,共有\((1+ \gcd(e-1,p-1))\times (1+ \gcd(e-1,q-1))\)个解。后面那篇文章提及在Recent Advances in RCA Cryptography这本书第69页的定理5.1有证明,不过我并没有获得该书的电子版,因此在这里展示前一篇文章的证明过程:
对于
使用中国剩余定理,有:
对式子
有两种情况:
- \(m \equiv 0 \pmod{p}\)
- \(m \ne 0 \pmod{p}\)
对情况2,对方程两边取对数有
即
因此log(m)应该为\(\frac{p-1}{\gcd(e-1,p-1)}\)的倍数,又\(log(m)\in \left ( 0,p \right )\) ,因此m有gcd(e-1,p-1)种取值。
综上,m有(1+gcd(e-1,p-1))种取值。
同理,对
m有(1+gcd(e-1,q-1))种取值。
总的来说m有\((1+ \gcd(e-1,p-1))\times (1+ \gcd(e-1,q-1))\)个解。
有了这个结论,那么解题就非常容易了,由于gcd(e,p-1)=1,显然e为奇数,那么gcd(e-1,p-1)和gcd(e-1,q-1)最小为2。
那么枚举e,使得gcd(e-1,p-1)和gcd(e-1,q-1)都为2,且\(\gcd(e,\phi(n))=1\)的e即为满足未加密信息m最少的加密指数。
完整代码如下:
点击查看代码
#求大公因数
def gcd(a, b):
if b == 0:
return a
else:
return gcd(b, a % b)
#枚举e
p, q, sum, e = 1009, 3643, 0, 3
phi = (p-1) * (q-1)
while (e < phi):
if gcd(e, phi)==1 and gcd(e-1, q-1)==2 and gcd(e-1, p-1)==2:
sum += e
e += 2
print("The sum of e is", sum)
T2
题目
Implement RSA
There are two annoying things about implementing RSA. Both of them involve key generation; the actual encryption/decryption in RSA is trivial.
First, you need to generate random primes. You can't just agree on a prime ahead of time, like you do in DH. You can write this algorithm yourself, but I just cheat and use OpenSSL's BN library to do the work.
The second is that you need an "invmod" operation (the multiplicative inverse), which is not an operation that is wired into your language. The algorithm is just a couple lines, but I always lose an hour getting it to work.
I recommend you not bother with primegen, but do take the time to get your own EGCD and invmod algorithm working.
Now:
1.Generate 2 random primes. We'll use small numbers to start, so you can just pick them out of a prime table. Call them "p" and "q".
2.Let n be p * q. Your RSA math is modulo n.
3.Let et be (p-1)*(q-1) (the "totient"). You need this value only for keygen.
4.Let e be 3.
5.Compute d = invmod(e, et). invmod(17, 3120) is 2753.
6.Your public key is [e, n]. Your private key is [d, n].
7.To encrypt: c = me%n. To decrypt: m = cd%n
8.Test this out with a number, like "42".
9.Repeat with bignum primes (keep e=3).
Finally, to encrypt a string, do something cheesy, like convert the string to hex and put "0x" on the front of it to turn it into a number. The math cares not how stupidly you feed it strings.
思路
就是实现RSA算法,按照步骤实现即可。要注意题目要求e=3,对于随机生成的p,q可能e与\(\phi(n)\)不互质,从而求不出逆,此时应重新生成p,q。由于这题只进行一次加解密,笔者为了方便并未使用快速幂算法。
完整代码如下:
点击查看代码
import random
from math import gcd
from sympy import mod_inverse
#素性检验
def is_prime(n):
"""判断一个数是否为素数"""
if n <= 1:
return False
if n == 2:
return True
if n % 2 == 0:
return False
for i in range(3, int(n ** 0.5) + 1, 2):
if n % i == 0:
return False
return True
#生成大素数
def generate_large_prime(bits=16):
"""生成一个大素数"""
while True:
num = random.getrandbits(bits)
if is_prime(num):
return num
# 生成RSA密钥对
def generate_rsa_keys(bits=16):
while True:
p = generate_large_prime(bits)
q = generate_large_prime(bits)
while p == q:
q = generate_large_prime(bits)
n = p * q
phi_n = (p - 1) * (q - 1)
e = 3
if gcd(e, phi_n) == 1:
break
d = mod_inverse(e, phi_n)
return (e, n), (d, n)
# 加密函数
def encrypt(m, pub_key):
e, n = pub_key
encrypted = [pow(ord(char), e, n) for char in m]
return encrypted
# 解密函数
def decrypt(c, priv_key):
d, n = priv_key
decrypted = ''.join(chr(pow(char, d, n)) for char in c)
return decrypted
# 测试
def rsa_test():
pub_key, priv_key = generate_rsa_keys(bits=16)
print("Public key:", pub_key)
print("Private key:", priv_key)
message = "Hello, RSA!"
# 加密消息
encrypted_message = encrypt(message, pub_key)
print("Ciphertext:", encrypted_message)
# 解密消息
decrypted_message = decrypt(encrypted_message, priv_key)
print("Plaintext:", decrypted_message)
# 测试
rsa_test()
总结
这次实验只涉及非对称密码中的RSA算法,需对RSA原理十分熟悉,同时也要求在数论上有一定基础。
我的所有代码存储在Github上Cryptography Assignment

浙公网安备 33010602011771号