es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

¿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
Tags:  ,

Answer

  1. Avatar for 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:

    from Crypto.Util.number import getPrime
    
    def generate_key():
        e = 65537
        while True:
            p = getPrime(1024)
            if pow(2, e, p) != 1:
                break
        while True:
            q = getPrime(1024)
            if q != p and pow(2, e, q) != 1:
                break
        n = p * q
        phi = (p - 1) * (q - 1)
        d = pow(e, -1, phi)
        return (e, n, d)
    
    def encrypt(message, pubkey):
        e, n = pubkey
        padded = message.to_bytes((message.bit_length() + 7) // 8, 'big')
        m = int.from_bytes(padded, 'big')
        c = pow(m, e, n)
        return c
    
    def decrypt(ciphertext, privkey):
        d, n = privkey
        m = pow(ciphertext, d, n)
        padded = m.to_bytes((m.bit_length() + 7) // 8, 'big')
        message = int.from_bytes(padded, 'big')
        return message
    
    msg = 42
    pubkey = generate_key()[:2] # descartar la clave privada
    ciphertext = encrypt(msg, pubkey)
    print(ciphertext)
    plaintext = decrypt(ciphertext, pubkey)
    print(plaintext) # debería imprimir 42
    

    Esta implementación genera dos números primos aleatorios p y q utilizando la función getPrime() de PyCryptodome, con una longitud de bits de 1024. Luego verifica que el valor 2^e (donde e=65537) no sea congruente a 1 módulo p o q para asegurarse de que sea seguro utilizar p y q para RSA. Luego calcula la clave privada d utilizando el algoritmo euclidiano extendido. Las funciones encrypt() y decrypt() utilizan relleno OAEP para prevenir ataques en tamaños de mensaje pequeños. Finalmente, cifra y descifra un mensaje msg y verifica que el mensaje descifrado sea igual al mensaje original. La salida debería ser la misma que la implementación original.

Comments are closed.