Saltar al contenido

¿Cómo puedo cifrar con una clave privada RSA en Python?

Solución:

Respuesta corta

  • el código que está utilizando no le permite hacer eso por razones de seguridad
  • código alternativo a continuación

Respuesta larga

Tenía curiosidad por tu problema y luego comencé a intentar codificar

Después de un tiempo me di cuenta de que si ejecuta este fragmento verá que funciona correctamente:

#!/usr/bin/env python

from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
import base64

def generate_keys():
    modulus_length = 1024

    key = RSA.generate(modulus_length)
    #print (key.exportKey())

    pub_key = key.publickey()
    #print (pub_key.exportKey())

    return key, pub_key

def encrypt_private_key(a_message, private_key):
    encryptor = PKCS1_OAEP.new(private_key)
    encrypted_msg = encryptor.encrypt(a_message)
    print(encrypted_msg)
    encoded_encrypted_msg = base64.b64encode(encrypted_msg)
    print(encoded_encrypted_msg)
    return encoded_encrypted_msg

def decrypt_public_key(encoded_encrypted_msg, public_key):
    encryptor = PKCS1_OAEP.new(public_key)
    decoded_encrypted_msg = base64.b64decode(encoded_encrypted_msg)
    print(decoded_encrypted_msg)
    decoded_decrypted_msg = encryptor.decrypt(decoded_encrypted_msg)
    print(decoded_decrypted_msg)
    #return decoded_decrypted_msg

def main():
  private, public = generate_keys()
  print (private)
  message = b'Hello world'
  encoded = encrypt_private_key(message, public)
  decrypt_public_key(encoded, private)

if __name__== "__main__":
  main()

pero si ahora cambias dos de las líneas finales [i.e. the role of the keys] dentro:

    encoded = encrypt_private_key(message, private)
    decrypt_public_key(encoded, public)

y vuelva a ejecutar el programa obtendrá el TypeError: No private key

Permítanme citar esta gran respuesta:

“Resulta que PyCrypto solo está tratando de evitar que confunda uno con el otro aquí, OpenSSL o Ruby OpenSSL le permiten, por ejemplo, hacer ambas cosas: public_encrypt / public_decrypt y private_encrypt / private_decrypt

[…]

Es necesario tener en cuenta cosas adicionales para que el resultado sea utilizable en la práctica. Y es por eso que hay un paquete de firmas dedicado en PyCrypto: esto efectivamente hace lo que describiste, pero también se ocupa de las cosas que mencioné “

Adaptando este enlace llegué al siguiente código que debería resolver tu duda:

# RSA helper class for pycrypto
# Copyright (c) Dennis Lee
# Date 21 Mar 2017

# Description:
# Python helper class to perform RSA encryption, decryption, 
# signing, verifying signatures & keys generation

# Dependencies Packages:
# pycrypto 

# Documentation:
# https://www.dlitz.net/software/pycrypto/api/2.6/

from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA512, SHA384, SHA256, SHA, MD5
from Crypto import Random
from base64 import b64encode, b64decode
import rsa

hash = "SHA-256"

def newkeys(keysize):
    random_generator = Random.new().read
    key = RSA.generate(keysize, random_generator)
    private, public = key, key.publickey()
    return public, private

def importKey(externKey):
    return RSA.importKey(externKey)

def getpublickey(priv_key):
    return priv_key.publickey()

def encrypt(message, pub_key):
    #RSA encryption protocol according to PKCS#1 OAEP
    cipher = PKCS1_OAEP.new(pub_key)
    return cipher.encrypt(message)

def decrypt(ciphertext, priv_key):
    #RSA encryption protocol according to PKCS#1 OAEP
    cipher = PKCS1_OAEP.new(priv_key)
    return cipher.decrypt(ciphertext)

def sign(message, priv_key, hashAlg="SHA-256"):
    global hash
    hash = hashAlg
    signer = PKCS1_v1_5.new(priv_key)
    if (hash == "SHA-512"):
        digest = SHA512.new()
    elif (hash == "SHA-384"):
        digest = SHA384.new()
    elif (hash == "SHA-256"):
        digest = SHA256.new()
    elif (hash == "SHA-1"):
        digest = SHA.new()
    else:
        digest = MD5.new()
    digest.update(message)
    return signer.sign(digest)

def verify(message, signature, pub_key):
    signer = PKCS1_v1_5.new(pub_key)
    if (hash == "SHA-512"):
        digest = SHA512.new()
    elif (hash == "SHA-384"):
        digest = SHA384.new()
    elif (hash == "SHA-256"):
        digest = SHA256.new()
    elif (hash == "SHA-1"):
        digest = SHA.new()
    else:
        digest = MD5.new()
    digest.update(message)
    return signer.verify(digest, signature)

def main():
    msg1 = b"Hello Tony, I am Jarvis!"
    msg2 = b"Hello Toni, I am Jarvis!"

    keysize = 2048

    (public, private) = rsa.newkeys(keysize)

    # https://docs.python.org/3/library/base64.html
    # encodes the bytes-like object s
    # returns bytes
    encrypted = b64encode(rsa.encrypt(msg1, private))
    # decodes the Base64 encoded bytes-like object or ASCII string s
    # returns the decoded bytes
    decrypted = rsa.decrypt(b64decode(encrypted), private)
    signature = b64encode(rsa.sign(msg1, private, "SHA-512"))

    verify = rsa.verify(msg1, b64decode(signature), public)

    #print(private.exportKey('PEM'))
    #print(public.exportKey('PEM'))
    print("Encrypted: " + encrypted.decode('ascii'))
    print("Decrypted: '%s'" % (decrypted))
    print("Signature: " + signature.decode('ascii'))
    print("Verify: %s" % verify)
    rsa.verify(msg2, b64decode(signature), public)

if __name__== "__main__":
    main()

Notas finales:

  • el último printafeitar ascii porque como se indica aquí “Sin embargo, en el caso de base64, todos los caracteres son caracteres ASCII válidos”
  • en este caso estamos usando la misma clave, la privada, tanto para encriptar como para desencriptar, así que sí: terminaríamos siendo simétricos pero …
  • pero, como se indica aquí, “La clave pública es PÚBLICA; es algo que compartiría fácilmente y, por lo tanto, se difundiría fácilmente. No hay valor agregado en ese caso en comparación con el uso de un cifrado simétrico y una clave compartida” más “Conceptualmente”, cifrado “con la clave privada es más útil para firmar un mensaje, mientras que el” descifrado “con la clave pública se utiliza para verificar el mensaje”
  • el mismo último principio idéntico se expresa en esta respuesta: “Normalmente […] decimos firmar con la clave privada y verificar con la clave pública “
¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *