Hazmat, Python and RSA Encryption

RSA has survived over 40 years and is still used in many applications. With public-key encryption, we generate a key pair: a public key and…

Photo by Dragonfly Ave on Unsplash

Hazmat, Python and RSA Encryption

RSA has survived over 40 years and is still used in many applications. With public-key encryption, we generate a key pair: a public key and a private key. If Bob wants to encrypt something for Alice, he will use her public key to encrypt the data, and then she will use her private key to decrypt it. In this case, we will use RSA encryption and use a public key to encrypt, and a private key to decrypt. Overall, in RSA, we generate a public key (e,N) and a private key (d,N). We encrypt a message (M) with C=M^e (mod N) and decrypt to P=C^d (mod N).

The following is the code to encrypt and decrypt. Within it we encrypt with:

ciphertext = pub.encrypt(message,padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()),algorithm=hashes.SHA256(),label=None))

and where we use OAEP (Optimal Asymmetric Encryption Padding) padding for the encryption process and create a SHA-256 hash. To decrypt we use the related private key, and defines the same padding and hashing methods:

plaintext = private_key.decrypt(ciphertext,padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()),algorithm=hashes.SHA256(),label=None))
print("\nDecrypted Message: ",plaintext.decode())

Normally, with RSA, we do not encrypt large amounts of data, and would typically use symmetric key encryption for that. The code is [here]:

from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives import hashes
import binascii
import sys

size=1024
message = b"Hello world"
if (len(sys.argv)>1):
message=str(sys.argv[1]).encode()
if (len(sys.argv)>2):
size=int(sys.argv[2])
print("Message: ",message)
print("Key size: ",size)
try:
private_key = rsa.generate_private_key(public_exponent=65537,key_size=size)

  pub = private_key.public_key()
  ciphertext = pub.encrypt(message,padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()),algorithm=hashes.SHA256(),label=None))
  print ("\nCiphertext:\n",binascii.b2a_hex(ciphertext).decode())
  plaintext = private_key.decrypt(ciphertext,padding.OAEP(mgf=padding.MGF1(algorithm=hashes.SHA256()),algorithm=hashes.SHA256(),label=None))
print("\nDecrypted Message: ",plaintext.decode())
  print("\n=== Private Key PEM format ===")
pem = private_key.private_bytes(encoding=serialization.Encoding.PEM,format=serialization.PrivateFormat.PKCS8,encryption_algorithm=serialization.NoEncryption())

  print ("\nPrivate key (PEM):\n",pem.decode())

  pem = pub.public_bytes(encoding=serialization.Encoding.PEM,format=serialization.PublicFormat.SubjectPublicKeyInfo).decode("utf-8")
  print("\n=== Public Key format ===")
print ("Public key (PEM):\n",pem)

except Exception as e:
print(e)

A sample run for a key size of 1,204 bit encryption keys is [here]:

Message:  b'Hello world'
Key size: 1024
Ciphertext:
e79ebd3f8ce2ae3f0bfe7d08ec484dda2d7aa1b8206f6d1a3b2aa57bcc0f9bf260a1474f55b794c69aa297874336d6574c4d43867768c9576c20a3b712f9dbe695d10b6eb322a4dc950c6b29fb0f16dc23f51ce4882aeb2899eb9e7f418a02677c17a4f344ba9c56ad095e1a704642a877e7f504db352530ce59c81906fbd773
Decrypted Message:  Hello world
=== Private Key PEM format ===
Private key (PEM):
-----BEGIN PRIVATE KEY-----
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAOuIIWDQJ3lsA2oA
dzteHvoEo/fJh/kjIYx6iWrcnsXze4tPXzwYnXI7VjUtes8rWRLeGEBdxlFTdYKv
xVl1aL/o74FimJEtR5TkqMoWAQSSPVEk5HG5yQ3JReSIiutggrnOA7Q0Pvf62TAr
TLcsn2aLpxeL4PkJtAdLBQkec85xAgMBAAECgYA++bgK/b0APzwudI9sxT69FM6O
q0j6+US4He9uLi0Zun93ATLyi5ZVe74SG+XxTKLVY6LSWwBysEEEP2EiCT2HRzxi
ShtzN/ITkSJ/ibEtPEm6UpB/zVi+t4/VIU5L7bpQgCR/Cys5fLptVOWV4DxVXD4r
ICM5gS9xyQeMRn5XrQJBAPgd74CtayW0Iq04KrOM1psFVjRky0EAUyU2r4IFvZWA
E6FJzLVTIdSHl4eA7dxfH3v4sg2YrHoM2jhr+FjX0CcCQQDzA9VA9NCww0UOUEhA
Y5Hbl8eRkc3rW35uYGVZ6zyMUWenj9OaS5djdc/fhTY6nI5nriwD+3WBVirjkMNP
+vOnAkA6WyAXjbIjvghh4VH5xOg8sbaiwAomEaN8ny4MULlUTjlPuAHTq+fLCtES
57oKGL1Y9Rc7p2r5kchJeOuCSdAFAkEAtCb7SJQ0wVWBNANADLvDvU7fm4LDbN7+
80Ry3h4NXNhcR1PQQmoXaJxF5iYS9ZBp4WK1Lp6TlbYTRXBj2j7nsQJBAL/8qGYn
+8AJK2oUlyAD/9BU/czZKTZtzp/9ACvOqC3Bs9IH4kk3w0pdnofLbaY+JQJS2Mcu
y1wsmaloS6qkFxc=
-----END PRIVATE KEY-----

=== Public Key format ===
Public key (PEM):
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDriCFg0Cd5bANqAHc7Xh76BKP3
yYf5IyGMeolq3J7F83uLT188GJ1yO1Y1LXrPK1kS3hhAXcZRU3WCr8VZdWi/6O+B
YpiRLUeU5KjKFgEEkj1RJORxuckNyUXkiIrrYIK5zgO0ND73+tkwK0y3LJ9mi6cX
i+D5CbQHSwUJHnPOcQIDAQAB
-----END PUBLIC KEY-----

And running code:

Conclusions

The usage of public keys is fundamental in proving identity, in digital signing, and in encrypting data. We often use it for digital signing. A common application is to encrypt data with a symmetric key. We can then encrypt the symmetric key with the public key of the owner, and where only the associated private key to decrypt it.