¿Por qué mis valores RSA para p, q, e = 3 resultan en una desencriptación sin éxito?
En realidad estoy tratando de resolver el desafío 39 del conjunto de criptopals en la configuración 5. Estoy intentando implementar RSA para algunos números primos más grandes p y q, con e = 3. He estado confundido por esto durante horas.
Para generar los primos, estoy utilizando una API para obtener cada primo. Sigo generando p hasta que gcd(p - 1, e) == 1
, y luego repito lo mismo para q hasta que gcd(q - 1, e) == 1
. También he probado gcd((p - 1) * (q - 1), e) == 1
. Por ejemplo, termino con p == 16226322033026808497 y q == 14712923008023747557.
Luego hago las operaciones matemáticas sencillas de RSA para calcular los otros valores, encripto el mensaje 42 (sin relleno), desencripto el cifrado obtenido y comparo el resultado con el mensaje original. He generado muchos p y q y nunca coinciden.
¿Alguien puede explicar por qué esto no funciona y ayudarme a generar algunos buenos parámetros, por favor?
Python:
p = 16226322033026808497
q = 14712923008023747557
e = 3
print(f'1 == gcd(p - 1, e) == {gcd(p - 1, e)}')
print(f'1 == gcd(p - 1, e) == {gcd(q - 1, e)}')
phi = (p - 1) * (q - 1)
print(f'phi == {phi}')
print(f'1 == gcd(phi, e) == {gcd(phi, e)}')
n = p * q
print(f'n == {n}')
d = invmod(e, phi)
print(f'd == {d}')
print(f'1 == (d * e) % phi == {(d * e) % phi}')
m = 42
c = pow(m, e, n);
print(f'c == m^e % n == {c}')
p = pow(c, d, n);
print(f'p == c^d % n == {p}')
Salida:
1 == gcd(p - 1, e) == 1
1 == gcd(p - 1, e) == 1
phi == 238736626775322802092761613952260035776
1 == gcd(phi, e) == 1
n == 238736626775322802123700858993310591829
d == 159157751183548534728507742634840023851
1 == (d * e) % phi == 1
c == m^e % n == 74088
p == c^d % n == 145835535613124975159078105657928869819
davy.ai
El problema con generar números primos grandes utilizando una API es que no es una forma segura de generar primos con fines criptográficos. Se recomienda utilizar un generador de números aleatorios seguro o un algoritmo generador de primos probado como Miller-Rabin o AKS.
Además, utilizar un exponente público pequeño como e=3 puede llevar a vulnerabilidades como el ataque de Wiener. Se recomienda utilizar un valor mayor para e como 65537.
Aquí hay una implementación actualizada que utiliza el módulo
Crypto.Util.number
en PyCryptodome para generar un número primo aleatorio seguro y un exponente público mayor. También incluye relleno para el mensaje para prevenir ataques en tamaños de mensaje pequeños.Python:
Esta implementación genera dos números primos aleatorios
p
yq
utilizando la funcióngetPrime()
de PyCryptodome, con una longitud de bits de 1024. Luego verifica que el valor2^e
(dondee=65537
) no sea congruente a 1 módulop
oq
para asegurarse de que sea seguro utilizarp
yq
para RSA. Luego calcula la clave privadad
utilizando el algoritmo euclidiano extendido. Las funcionesencrypt()
ydecrypt()
utilizan relleno OAEP para prevenir ataques en tamaños de mensaje pequeños. Finalmente, cifra y descifra un mensajemsg
y verifica que el mensaje descifrado sea igual al mensaje original. La salida debería ser la misma que la implementación original.