Algoritmo RSA
RSA es un algoritmo de cifrado asimétrico. Si A quiere comunicarse con B, A utiliza la clave pública A para cifrar y transfiere el texto cifrado a B, y B utiliza la clave privada B para descifrar el texto sin formato, donde la clave pública se transmite en la red. La clave privada solo es propiedad de B y no se transmite en la red, por lo que incluso si se conoce la clave pública A, la información transmitida no se puede descifrar
Principio del algoritmo RSA e implementación del código Python
1. Genera claves públicas y privadas
1.1 Dados dos números primos P, Q
Cuanto más grandes sean P y Q aquí, más seguro será el algoritmo. Para la conveniencia de la descripción, dado P = 67 y Q = 71, entonces su producto n = 4757
1.2 Calcular la función de Euler φ (n) de n
Según la definición de la función de Euler, φ (n) es igual al número de enteros positivos menores o iguales an que son relativamente primos an , y como P * Q = n y PQ son todos números primos, φ (n) = (P -1) (Q-1) = 66 * 70 = 4620
1.3 Seleccione aleatoriamente un número entero e (1 <e <m) ye y m son primos relativos
Aquí e = 101 se selecciona al azar. Tenga en cuenta que cuando e = m, las claves pública y privada serán las mismas
1.4 Dado un número entero d, haga (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
Una vez completado el cálculo, se obtienen la clave pública (n, e) = (4757,101) y la clave privada (n, d) = (4757,1601) . Según el efecto del algoritmo RSA, nadie conoce la clave privada excepto el receptor . Entonces, ¿puede obtener la clave privada a través de la clave pública?
已知(e*d)%m=1,已知n,e,那么要求d只需要求出n
而我们知道m是n的欧拉函数φ(n),想要知道m就必须将n分解成两个质数的乘积
这里由于数比较小,我们很容易分解出PQ的值,而随着n的增大,分解会变得异常困难
2. Cifrado para generar texto cifrado
Suponiendo que el número cifrado es a,
convertir a en int es 97. El
proceso de cálculo es el siguiente:
97 ^ 101% 4757 = 3589
3. Descifre el texto cifrado
Según la fórmula
a ^ d% n = b
Podemos obtener el texto sin formato
Implementación de código Python
Dado que el lenguaje C no admite números grandes, es muy problemático usar el lenguaje C para implementar el código Python aquí
# -*- 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)
Ataque de modo común RSA
Suponga que hay una pieza de información m, que está encriptada por dos usuarios diferentes usando claves públicas (la e de los dos usuarios es generalmente diferente y el módulo n es generalmente el mismo)
c1 = m^e1 mod n
c2 = m^e2 mod n
Tengo dos textos cifrados diferentes c1, c2
Ataque en modo común Esto obtiene estos dos textos cifrados c1, c2, porque la clave pública es pública (e1, e2, n) se conoce
Entonces el atacante conoce la siguiente información en total
gcd(e1, e2) = 1
m = c1^d1 mod n
m = c2^d2 mod n
Entonces de acuerdo con lo anterior, el texto llano m se puede obtener directamente, porque gcd(e1,e2)
entonces hay enteros s1, s2 e1*s1+e2*s2=1
, y porque
c1=m^e1 mod n
c2=m^e2 mod n
y entonces:
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
Plantilla de código:
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()