Encrypt a signed message with RSA in the cryptography Python library

931 views Asked by At

I'm new to cryptography, sorry if I'm just trying to do something stupid.

So, don't hesitate to say if I tried to do something wrong or not in the right way or whatever it is.

I want to use RSA and I have two people: Alice and Bob.

At first, I wanted to encrypt the message with Alice's private key and later encrypt the encrypted message with Bob's public key, to safeguard the integrity/authenticity and confidentiality of the message.

I have learned that it is not possible to encrypt with the private key, the message needs to be signed and then verified.

I have seen that I need the signed message and the message non-signed to verify the signature. According to my research at this point, I have two options:

  • Encrypt two messages one signed and one not and check the signature after the decryption,
  • Encrypt the concatenation of the message and the signed message with a separator, decrypt the text, get both with the separator, and after that check the signature.

I have decided the second option.

But with this method I have an error with the length that can be encrypted with the RSA key, maybe the right choice is to do as @Topaco said :

  • Encrypt the message
  • Sign the encrypted message
  • Give both to Bob
  • Verify the signature with the messages
  • Finally, decrypt the encrypted message?

But with this method, we have to send 2 different messages to Bob (?) I feel like it's weird

Here is my code :

from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.primitives import serialization, hashes
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives.asymmetric import rsa, utils

# Generate private key for Alice
alice_private_key = rsa.generate_private_key(public_exponent=65537, key_size=4096)

# Get the public key for Alice
alice_public_key = alice_private_key.public_key()

# Generate private key for Bob
bob_private_key = rsa.generate_private_key(public_exponent=65537, key_size=4096)

# Get the public key for Bob
bob_public_key = bob_private_key.public_key()

# Sign the message using Alice's private key
message = b"Hello, world!"
signature = alice_private_key.sign(
    message,
    padding.PSS(
        mgf=padding.MGF1(hashes.SHA256()),
        salt_length=padding.PSS.MAX_LENGTH
    ),
    hashes.SHA256()
)

# Concatenate the message and the signature using a separator
separator = b'|'
signed_message = message + separator + signature

# Encrypt the signed message using Bob's public key
ciphertext = bob_public_key.encrypt(
    signed_message,
    padding.OAEP(
        mgf=padding.MGF1(algorithm=hashes.SHA256()),
        algorithm=hashes.SHA256(),
        label=None
    )
)

# Print the ciphertext
print(ciphertext)

# Decrypt the package using Bob's private key
plaintext = bob_private_key.decrypt(
    ciphertext,
    padding.OAEP(
        mgf=padding.MGF1(algorithm=hashes.SHA256()),
        algorithm=hashes.SHA256(),
        label=None
    )
)

# Get the signature and message
# signature_length = 256  # assuming the signature is 256 bytes long
# signature = plaintext[-signature_length:]
# message = plaintext[:-signature_length]
# Split the plaintext to get the signature and message using the separator
message, signature = plaintext.split(separator)

# Verify the signature using Alice's public key
try:
    alice_public_key.verify(
        signature,
        message,
        padding.PSS(
            mgf=padding.MGF1(hashes.SHA256()),
            salt_length=padding.PSS.MAX_LENGTH
        ),
        hashes.SHA256()
    )
    print("Message send by Alice !")
except InvalidSignature as e:
    print("Message not send by Alice !")

Thank you in advance for your help !

1

There are 1 answers

0
BOSS_ladis On

With help from @Topaco the result is the working code below. But it still feels weird to me to have to send 2 messages in order to ensure the authenticity / integrity and the confidentiality of the message.

from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives.asymmetric import rsa

# Generate private key for Alice
alice_private_key = rsa.generate_private_key(public_exponent=65537, key_size=4096)

# Get the public key for Alice
alice_public_key = alice_private_key.public_key()

# Generate private key for Bob
bob_private_key = rsa.generate_private_key(public_exponent=65537, key_size=4096)

# Get the public key for Bob
bob_public_key = bob_private_key.public_key()

message = b"Hello, world!"
print(message)

# Encrypt the message using Bob's public key
encoded_message = bob_public_key.encrypt(
    message,
    padding.OAEP(
        mgf=padding.MGF1(algorithm=hashes.SHA256()),
        algorithm=hashes.SHA256(),
        label=None
    )
)

# Sign the encoded message using the alice's private key
signed_encoded_message = alice_private_key.sign(
    encoded_message,
    padding.PSS(
        mgf=padding.MGF1(hashes.SHA256()),
        salt_length=padding.PSS.MAX_LENGTH
    ),
    hashes.SHA256()
)

# Print the encoded_message (To virtually send these to Bob)
print(encoded_message)
print(signed_encoded_message)

# Verify the signature using Alice's public key
alice_public_key.verify(
    signed_encoded_message,
    encoded_message,
    padding.PSS(
        mgf=padding.MGF1(hashes.SHA256()),
        salt_length=padding.PSS.MAX_LENGTH
    ),
    hashes.SHA256()
)

# If the previous block doesn't raise an InvalidSignature exception
# we can decrypt the encoded_message

# Decrypt the package using Bob's private key
decoded_message = bob_private_key.decrypt(
    encoded_message,
    padding.OAEP(
        mgf=padding.MGF1(algorithm=hashes.SHA256()),
        algorithm=hashes.SHA256(),
        label=None
    )
)

# Bob have the Alice's message
print(decoded_message)