1 < e < ( p − 1 ) ( q − 1 ) g c d ( e , ( p − 1 ) ( q − 1 ) ) = 1 1
d e = 1 m o d ( p − 1 ) ∗ ( q − 1 ) de=1~mod~(p-1)*(q-1) de=1 mod (p−1)∗(q−1)
def get_prime(len_bit):
"""
随机获取一个二进制位长len_bit的整数
"""
prm = (randint(2 ** (len_bit - 1), 2 ** len_bit) + 1) | 1
# 利用或运算保证prm是一个奇数
while not isPrime(prm):
prm += 2
return prm
特 性 : 有 1 得 1 , 全 0 才 0 0 ∣ 0 = 0 ; 0 ∣ 1 = 1 ; 1 ∣ 0 = 0 ; 1 ∣ 1 = 1 应 用 : 某 位 赋 值 1 特性:有1得1,全0才0\\ 0|0=0;~~ 0|1=1;\\ 1|0=0;~~ 1|1=1\\ 应用:某位赋值1 特性:有1得1,全0才00∣0=0; 0∣1=1;1∣0=0; 1∣1=1应用:某位赋值1
费马小定理:
设 p 是 一 个 素 数 , 那 么 ∀ a ∈ Z 有 a p ≡ a ( m o d p ) 设p是一个素数,那么\forall a\in \mathbb{Z}\\ 有~a^p\equiv a(mod~p) 设p是一个素数,那么∀a∈Z有 ap≡a(mod p)
二次探测定理:
如 果 p 是 一 个 素 数 , 0 < x < p , 则 方 程 x 2 ≡ 1 ( m o d p ) 的 解 为 : x ≡ ± 1 ( m o d p ) 反 之 , 如 果 方 程 的 解 不 是 x ≡ ± 1 ( m o d p ) , 那 么 p 不 是 素 数 如果p是一个素数,0
Miller-rabin witness:
设 n 是 一 个 奇 数 , 则 n − 1 = 2 k q , 其 中 q 是 奇 数 , 取 满 足 g c d ( a , n ) = 1 的 a 如 下 条 件 满 足 , 则 称 a 是 n 的 M i l l e r − R a b i n w i t n e s s : 1. a q ≢ 1 ( m o d n ) 2. a 2 i q ≢ − 1 ( m o d n ) i = 0 , 1 , . . . , k − 1 设n是一个奇数,则n-1=2^kq,其中q是奇数,取满足gcd(a,n)=1的a\\ 如下条件满足,则称a是n的Miller-Rabin witness:\\ 1.a^q\not\equiv1(mod~n)\\ 2.a^{2^iq}\not\equiv-1(mod~n)~i=0,1,...,k-1 设n是一个奇数,则n−1=2kq,其中q是奇数,取满足gcd(a,n)=1的a如下条件满足,则称a是n的Miller−Rabinwitness:1.aq≡1(mod n)2.a2iq≡−1(mod n) i=0,1,...,k−1
def isPrime(n):
"""
miller-rabin检验,返回是否是质数
"""
if n == 2 or n == 3:
return True
if not n & 1:
return False
m, q = n - 1, 0
while not m & 1:
m >>= 1
q += 1
rd, seed1, seed2 = 20011224, 998244353, 20217371
for i in range(0, 30):
rd = rd * seed1 + seed2
if rd < 0:
rd = -rd
a = rd % (n - 1) + 1
tmp = fast_power(a, m, n)
for j in range(0, q):
ans = tmp ** 2 % n
if ans == 1:
if tmp != 1 and tmp != n - 1:
return False
break
tmp = ans
if ans != 1:
return False
return True
def fast_power(base, power, n=0):
"""
快速(模)幂运算
n的默认值为0:快速幂运算
n>0:快速模幂运算
"""
if power <= 0:
raise ValueError("power must be postive")
result = 1
if n == 0:
while power > 0:
if power & 1:
result *= base
power >>= 1
base *= base
else:
while power > 0:
if power & 1:
result = result * base % n
power >>= 1
base = base ** 2 % n
return result
def get_key(len_bit):
"""
生成RSA公私钥
params: len_bit:p/q的二进制基础长度,
return: (n, e), (n, d), (p, q)
"""
p = get_prime(len_bit + 1)
q = get_prime(len_bit + 3)
# 保证p/q不是很接近
n = p * q
phi = (p - 1) * (q - 1)
e = get_prime(16)
while gcd(e, phi) > 1:
e = get_prime(16)
d = invmod(e, phi)
with open("public_key.txt", "w") as f:
f.write(f"n = {n}\n")
f.write(f"e = {e}\n")
with open("private_key.txt", "w") as f:
f.write(f"n = {n}\n")
f.write(f"d = {d}\n")
return (n, e), (n, d), (p, q)
逆元实现:
扩展欧式算法:
def Egcd(a, b):
"""
扩展欧拉算法:au+bv=g
params: a, b
return: x = (g, u, v)
"""
x = [a, 1, 0]
y = [b, 0, 1]
while y[0] != 0:
q = x[0] // y[0]
for i in range(0, 3):
x[i] = x[i] - q * y[i]
tmp = x[:]
x = y[:]
y = tmp[:]
return x
逆元判断:
def invmod(a, n):
"""
求a mod n 的逆元
"""
if n < 2:
raise ValueError("n must be bigger than 1")
g, x, y = Egcd(a, n)
if g != 1:
raise ValueError("no invmod")
else:
return x % n
def rsa_encrypt(m, public_key):
"""
RSA加密函数
params:公钥publickey = (n, e) 明文m(整数形式)
return:密文c
"""
n, e = public_key[0], public_key[1]
if m < 0:
raise ValueError("msg is negative")
elif m > n:
raise ValueError("msg is too long")
else:
c = fast_power(m, e, n)
return c
def rsa_decrypt(c, private_key):
"""
RSA解密函数
params:私钥private_key = (n, d) 密文c(整数)
return:明文m
"""
n, d = private_key[0], private_key[1]
if c < 0:
raise ValueError("cpr is negative")
elif c > n:
raise ValueError("cpr is too long")
else:
m = fast_power(c, d, n)
return m
CRT(中国剩余定理):
数学原理:
设 m 1 , m 2 , . . . , m r 是 两 两 互 素 的 自 然 数 , 令 m = m 1 m 2 . . . m r , M i = m m i , i = 1 , . . . , r , 则 方 程 组 : { x ≡ b 1 ( m o d m 1 ) x ≡ b 2 ( m o d m 2 ) . . . x ≡ b r ( m o d m r ) 的 解 为 : x ≡ M 1 ′ M 1 b 1 + M 1 ′ M 2 b 2 + . . . M r ′ M r b r ( m o d m ) 即 x ≡ ∑ i = 1 r M i ′ M i b i ( m o d m ) 其 中 M i ′ 满 足 M i ′ M i ≡ 1 ( m o d m i ) 设m_1,m_2,...,m_r是两两互素的自然数,\\ 令m=m_1m_2...m_r,~M_i=\frac{m}{m_i},~i=1,...,r,则方程组:\\ \begin{cases} x\equiv b_1~(mod~m_1)\\ x\equiv b_2~(mod~m_2)\\ ~~ ...\\ x\equiv b_r~(mod~m_r) \end{cases} ~~的解为:\\ x\equiv M_1'M_1b_1+M_1'M_2b_2+...M_r'M_rb_r~(mod~m)\\ 即~x\equiv \sum_{i=1}^r~M_i'M_ib_i~(mod~m)\\ 其中~M_i'~满足~M_i'M_i\equiv 1~(mod~ m_i) 设m1,m2,...,mr是两两互素的自然数,令m=m1m2...mr, Mi=mim, i=1,...,r,则方程组:⎩⎪⎪⎪⎨⎪⎪⎪⎧x≡b1 (mod m1)x≡b2 (mod m2) ...x≡br (mod mr) 的解为:x≡M1′M1b1+M1′M2b2+...Mr′Mrbr (mod m)即 x≡i=1∑r Mi′Mibi (mod m)其中 Mi′ 满足 Mi′Mi≡1 (mod mi)
代码实现:
def crt(cpr_lst, n_lst):
"""
中国剩余定理求解: x = c (mod n)
params:
cpr-lst 余数c列表
n_lst 模数n列表
return: x
"""
# 累积 m = n1*n2*...*nk
m = reduce(lambda x, y: x * y, (ni for ni in n_lst))
result = 0
data = zip(cpr_lst, n_lst)
for ci, ni in data:
mi = m // ni
di = invmod(mi, ni)
result += (ci * mi * di) % m
return result % m
CRT加速解密计算:
def rsa_decrypt_crt(c, d, prime_pair):
"""
CRT加速解密计算(已知p、q)
"""
p, q = prime_pair[0], prime_pair[1]
c_lst = [fast_power(c, d % (p - 1), p), fast_power(c, d % (q - 1), q)]
n_lst = [p, q]
return crt(c_lst, n_lst)
对 明 文 m 使 用 h a s h 得 到 信 息 摘 要 d i g e s t , 之 后 对 信 息 摘 要 使 用 私 钥 进 行 加 密 得 到 签 名 s ≡ d i g e s t d ( m o d n ) 对明文m使用hash得到信息摘要digest,之后对信息摘要使用私钥进行加密得到签名\\s\equiv digest^d(mod~n) 对明文m使用hash得到信息摘要digest,之后对信息摘要使用私钥进行加密得到签名s≡digestd(mod n)
import hashlib
dgst = s2n(hashlib.sha256(msg).digest())
def rsa_sign(digest, private_key):
"""
RSA签名生成函数:对信息摘要使用私钥加密生成签名
return:签名signature
"""
signature = rsa_encrypt(digest, private_key)
with open("signature.txt", "w") as f:
f.write(f"sgn = {signature}")
return signature
对 签 名 使 用 公 钥 进 行 解 密 与 信 息 摘 要 进 行 比 对 , 如 果 一 致 则 验 证 通 过 d g s t ≡ s e ( m o d n ) 对签名使用公钥进行解密与信息摘要进行比对,如果一致则验证通过\\ dgst \equiv s^e(mod~n) 对签名使用公钥进行解密与信息摘要进行比对,如果一致则验证通过dgst≡se(mod n)
def rsa_verify(digest, signature, public_key):
"""
RSA签名验证函数:使用公钥对签名验证
return:验证是否成功(bool)
"""
if digest == rsa_decrypt(signature, public_key):
return True
else:
return False
def get_pubkey(pubfile="public_key.txt"):
"""
公钥文件读取
params:默认公钥文件名"public_key.txt"
return:公钥(n,e)
"""
with open(pubfile, "r") as f:
for line in f:
if line.startswith('n'):
n = line.split(' ')[-1]
if line.startswith('e'):
e = line.split(' ')[-1]
return n, e
def get_privkey(privfile="private_key.txt"):
"""
私钥文件读取
params:默认私钥文件名:"private_key.txt"
return:私钥(n,d)
"""
with open(privfile, "r") as f:
for line in f:
if line.startswith('n'):
n = line.split(' ')[-1]
if line.startswith('d'):
d = line.split(' ')[-1]
return n, d
def type_choose(path="message.txt"):
"""
加密对象类型选择(文件或者非文件)
"""
choice = int(input("plz select the Encryption Type:\n1. file 2. not file:"))
if choice == 1:
path = input("plz input the filename or filepath:\n")
with open(path, "r") as f:
message = f.read()
else:
message = input("plz input the content to be encrypted:")
return message.encode("utf-8")
if __name__ == "__main__":
# msg = "£.RSA{ha6a_I_am_lzh_i_want_t0_6ai1an}"
msg = type_choose()
dgst = s2n(hashlib.sha256(msg).digest())
pubkey, privkey, prmpair = get_key(1024)
sgn = rsa_sign(dgst, privkey)
cpr = rsa_encrypt(s2n(msg), pubkey)
print(f"cipher is {cpr}")
print(f"verification is {rsa_verify(dgst, sgn, pubkey)}")
t1 = time.time()
rcvr = n2s(rsa_decrypt(cpr, privkey)).decode("utf-8")
t2 = time.time()
print(f"message is recovered: {rcvr},time is {t2-t1:.8f}")
t1 = time.time()
rcvr_crt = n2s(rsa_decrypt_crt(cpr, privkey[1], prmpair)).decode("utf-8")
t2 = time.time()
print(f"message is recovered by CRT: {rcvr_crt},time is: {t2-t1:.8f}")
否 则 当 p 和 q 很 接 近 的 时 候 , 在 已 知 N 得 情 况 下 , 不 妨 假 设 p > q 由 ( p + q 2 ) 2 = N + ( p − q 2 ) 2 当 左 边 可 开 放 时 , 可 求 出 p − q 进 而 求 得 p / q 否则当p和q很接近的时候,在已知N得情况下,不妨假设p>q\\ 由 \left( \frac{p+q}{2} \right)^2=N+ \left( \frac{p-q}{2} \right)^2\\ 当左边可开放时,可求出p-q进而求得p/q 否则当p和q很接近的时候,在已知N得情况下,不妨假设p>q由(2p+q)2=N+(2p−q)2当左边可开放时,可求出p−q进而求得p/q
原因是我们可以使用满足 d e ≡ 1 ( m o d ( p − 1 ) ( q − 1 ) g ) de\equiv1(mod~\frac{(p-1)(q-1)}{g}) de≡1(mod g(p−1)(q−1))的较小的d来加快计算,其中 g = g c d ( p − 1 , q − 1 ) g=gcd(p-1,q-1) g=gcd(p−1,q−1)越大,求解得到的d越小越不安全。