Experimenting with Asymmetric Encryption and Decryption using RSA keys

The public key and the private key in the keypair are inverse keys. That is, data encrypted by the public key can only be successfully decrypted by using the private key; data encrypted by the private key can only be decrypted by the public key.

As shown in Figure 5.1 of the textbook (copied below), to send a confidential message to Bob using asymmetric cryptography, Alice uses Bob’s public key to encrypt the plaintext. The generated ciphertext from the encryption will then be made available to Bob. When Bob has accessed the ciphertext, he will use his own private key to decrypt the ciphertext in order to retrieve the original plaintext message.

Step A: Run the following script to generate an RSA keypair and save the keys into files (the public key in public_key.pem and the private key in private_key.pem.

Assumption: The generated private key and public key belongs to Bob, and the public key is made available to Alice.

NOTE: Normally, keys are generated using external tools such as openssl, keytool, etc.

# script: asymTest.py

from cryptography.hazmat.backends import default_backend

from cryptography.hazmat.primitives import serialization

from cryptography.hazmat.primitives.asymmetric import rsa

 

# key generations

private_key = rsa.generate_private_key(

 public_exponent=65537,

 key_size=3072,

 backend=default_backend(), )

 

public_key = private_key.public_key()

 

#serialization of the keys

private_bytes = private_key.private_bytes(

 encoding=serialization.Encoding.PEM,

 format=serialization.PrivateFormat.PKCS8,

 encryption_algorithm=serialization.NoEncryption(), )

 

# Save the private key into the file private_key.pem.

# If the file exists, overwirte it.

with open('private_key.pem', 'wb') as private_file:

 private_file.write(private_bytes)

public_bytes = public_key.public_bytes(

 encoding=serialization.Encoding.PEM,

 format=serialization.PublicFormat.SubjectPublicKeyInfo, )

 

# Save the public key into the file public_key.pem.

# If the file exists, overwirte it.

with open('public_key.pem', 'wb') as public_file:

 public_file.write(public_bytes)

 

Figure 1: The script of generating an RSA keypair and saving the private key into private_key.pem and the public key into public_key.pem

The screen output of running the above script is shown in Figure 2.

Figure 2: Generating an RSA keypair and save the private key into private_key.pem and public key into public_key.pem

Step B: To generate a confidential file that only Bob can access, Alice will use Bob’s public key to encrypt a plaintext message and then saves the generated ciphertext in the file ciphertext.dat.

Assumption: The ciphertext.dat file will made available to Bob.

The script to generate the ciphertext file is shown in Figure 3.

# script: AliceEncrypt.py

from cryptography.hazmat.primitives import hashes

from cryptography.hazmat.primitives.asymmetric import padding

from cryptography.hazmat.backends import default_backend

from cryptography.hazmat.primitives import serialization

 

# Deserialization of Bob's public key

with open('public_key.pem', 'rb') as public_file:

 loaded_public_key = serialization.load_pem_public_key(

 public_file.read(),

 backend=default_backend()

 )

 

padding_config = padding.OAEP(

 mgf=padding.MGF1(algorithm=hashes.SHA256()),

 algorithm=hashes.SHA256(),

 label=None, )

 

plaintext = b'message from Alice to Bob'

ciphertext = loaded_public_key.encrypt(

 plaintext=plaintext,

 padding=padding_config, )

 

print("ciphertext (encrypted by Alice using Bob's public key): ",

     ciphertext)

# Save the ciphertext to a file

with open('ciphertext.dat', 'wb') as encrypted_file:

              encrypted_file.write(ciphertext)

Figure 3: The script of generating the ciphertext.dat file from a plaintext message

The screen output of running the above script is shown in Figure 4.

Figure 4: The screen output of generating the ciphertext.dat file from a plaintext message

 

Step C: Assuming the ciphertext.dat file is made available to Bob (via file transfer or messaging), Bob will use his private key to decrypt the ciphertext in that file.

The script of loading the private key and the ciphertext is shown in Figure 5. Once loaded, the private key is used to decrypt the ciphertext.

# script:BobDecrypt.py

 from cryptography.hazmat.primitives import hashes

from cryptography.hazmat.primitives.asymmetric import padding

from cryptography.hazmat.backends import default_backend

from cryptography.hazmat.primitives import serialization

 

# Deserialization of Bob's private key

with open('private_key.pem', 'rb') as private_file:

 loaded_private_key = serialization.load_pem_private_key(

 private_file.read(),

 password=None,

 backend=default_backend()

 )

 

padding_config = padding.OAEP(

 mgf=padding.MGF1(algorithm=hashes.SHA256()),

 algorithm=hashes.SHA256(),

 label=None, )

 

# Read the ciphertext file

with open('ciphertext.dat', 'rb') as ciphertext_file:

              ciphertext = ciphertext_file.read()

             

decrypted_by_private_key = loaded_private_key.decrypt(

 ciphertext=ciphertext,

 padding=padding_config)

 

#assert decrypted_by_private_key == plaintext

print("The decrypted ciphertext: ", decrypted_by_private_key)

Figure 5: The screen output of generating the ciphertext.dat file from a plaintext message

The screen output of running the above script is shown in Figure 6.

Figure 6: The screen output of generating the ciphertext.dat file from a plaintext message