简体   繁体   中英

Encrypt a signed message with RSA in the cryptography Python library

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 !

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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM