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
print
afeitarascii
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 “