How Can I Encrypt With A Rsa Private Key In Python?
Solution 1:
Short answer
- the code that you are using doesn't allow you to do that for security reasons
- alternative code below
Long answer
I was curious about your problem and then I started to try to code
After a while I realized that if you run this snippet you will see that it correctly works:
#!/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()
but if you now change two of the final lines [i.e. the role of the keys] into:
encoded = encrypt_private_key(message, private)
decrypt_public_key(encoded, public)
and rerun the program you will get the TypeError: No private key
Let me quote from this great answer:
"As it turns out, PyCrypto is only trying to prevent you from mistaking one for the other here, OpenSSL or Ruby OpenSSL allow you for example to do both: public_encrypt/public_decrypt and private_encrypt/private_decrypt
[...]
Additional things need to be taken care of to make the result usable in practice. And that's why there is a dedicated signature package in PyCrypto - this effectively does what you described, but also additionally takes care of the things I mentioned"
Adapting this link I came to the following code that should solve your question:
# 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"defnewkeys(keysize):
random_generator = Random.new().read
key = RSA.generate(keysize, random_generator)
private, public = key, key.publickey()
return public, private
defimportKey(externKey):
return RSA.importKey(externKey)
defgetpublickey(priv_key):
return priv_key.publickey()
defencrypt(message, pub_key):
#RSA encryption protocol according to PKCS#1 OAEP
cipher = PKCS1_OAEP.new(pub_key)
return cipher.encrypt(message)
defdecrypt(ciphertext, priv_key):
#RSA encryption protocol according to PKCS#1 OAEP
cipher = PKCS1_OAEP.new(priv_key)
return cipher.decrypt(ciphertext)
defsign(message, priv_key, hashAlg="SHA-256"):
globalhashhash = 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)
defverify(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)
defmain():
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()
Final notes:
- the last
print
s haveascii
because as stated here "In case of base64 however, all characters are valid ASCII characters" - in this case we are using the same key - the private one - both for encrypting and decrypting, so yes: we would end up to be symmetric but...
- but - as stated here - "The public key is PUBLIC - it's something you would readily share and thus would be easily disseminated. There's no added value in that case compared to using a symmetric cipher and a shared key" plus "Conceptually, "encrypting" with the private key is more useful for signing a message whereas the "decryption" using the public key is used for verifying the message"
- the same identical last principle is expressed in this answer - "Typically [...] we say sign with the private key and verify with the public key"
Solution 2:
Looks like pycrypto
has not been under active development since 2014 and support ended at python 3.3. cryptography
seems like the standard now.
Using cryptography
:
from cryptography.hazmat.primitivesimport serialization
from cryptography.hazmat.primitives.asymmetricimport rsa
from cryptography.hazmat.backendsimport default_backend
password = b'thepassword'
key = rsa.generate_private_key(
backend=default_backend(),
public_exponent=65537,
key_size=2048
)
private_key = key.private_bytes(
serialization.Encoding.PEM,
serialization.PrivateFormat.PKCS8,
serialization.BestAvailableEncryption(password)
)
public_key = key.public_key().public_bytes(
serialization.Encoding.OpenSSH,
serialization.PublicFormat.OpenSSH
)
Solution 3:
What you are describing is called message signing and it uses private/public keys to verify that the message did come from the claimed sender and that it has not been tampered with en route. You don't have to "invent" these methods ...
https://medium.com/@securegns/implementing-asymmetric-encryption-to-secure-your-project-35368049cb5f
Post a Comment for "How Can I Encrypt With A Rsa Private Key In Python?"