1

I am new to the world of encryption and I was wondering if my solution for encrypting/decrypting data is okay.

When creating this, I referenced the API documentation from PyCryptodome: https://pycryptodome.readthedocs.io/en/latest/src/api.html

For reference, I have a client-server application and it is assumed the sender already knows the host's public key.

  1. Is it proper to send the session key, nonce, and tag to the host?
  2. Is there anything vital that I am missing/overlooked?
def send_data(socket, key, data):
    enc_session_key, nonce, tag, ciphertext = encrypt_data(key, data)
    
    encapsulated_data = [enc_session_key, nonce, tag, ciphertext]
    
    data = pickle.dumps(encapsulated_data)
    
    stream = bytes(data)
    stream_length = len(stream)
    socket.sendall(struct.pack("<Q", stream_length))
    socket.sendall(stream)


def encrypt_data(key, data):
    recipient_key = key
    session_key = get_random_bytes(16)

    # Encrypt the session key with the public RSA key
    cipher_rsa = PKCS1_OAEP.new(recipient_key)
    enc_session_key = cipher_rsa.encrypt(session_key)

    # Encrypt the data with the AES session key
    cipher_aes = AES.new(session_key, AES.MODE_EAX)
    ciphertext, tag = cipher_aes.encrypt_and_digest(data)

    return enc_session_key, cipher_aes.nonce, tag, ciphertext

def decrypt_data(enc_session_key, nonce, tag, ciphertext):
    if not os.path.exists(PRIVATE_PATH):
        return None

    private_key = RSA.import_key(open(PRIVATE_PATH).read())

    # Decrypt the session key with the private RSA key
    cipher_rsa = PKCS1_OAEP.new(private_key)
    session_key = cipher_rsa.decrypt(enc_session_key)

    # Decrypt the data with the AES session key
    cipher_aes = AES.new(session_key, AES.MODE_EAX, nonce)
    data = cipher_aes.decrypt_and_verify(ciphertext, tag)

    return data


Here, send_data() is called passing in the socket, public key of the reciever, and the data they would like to send.

It is assumed decrypt_data() is called after a host recieves the data and calls pickle.loads() to get the list sent from send_data().

Thank you!!

1 Answer 1

0

It is proper to send the session key, tag and nonce to the host. I've used Python (and PyCryptodome) for encryption, but am no expert. This is how I would write your script:

import os
import pickle
import struct
from Crypto.PublicKey import RSA
from Crypto.Cipher import AES, PKCS1_OAEP
from Crypto.Random import get_random_bytes

PRIVATE_PATH = 'private_key.pem'

def send_data(socket, key, data):
    enc_session_key, nonce, tag, ciphertext = encrypt_data(key, data)
    encapsulated_data = [enc_session_key, nonce, tag, ciphertext]
    serialized_data = pickle.dumps(encapsulated_data)
    socket.sendall(struct.pack("<Q", len(serialized_data)) + serialized_data)

def encrypt_data(key, data, key_size=16):
    session_key = get_random_bytes(key_size)
    cipher_rsa = PKCS1_OAEP.new(key)
    enc_session_key = cipher_rsa.encrypt(session_key)
    cipher_aes = AES.new(session_key, AES.MODE_EAX)
    ciphertext, tag = cipher_aes.encrypt_and_digest(data)

    return enc_session_key, cipher_aes.nonce, tag, ciphertext

def decrypt_data(enc_session_key, nonce, tag, ciphertext):
    try:
        private_key = RSA.import_key(open(PRIVATE_PATH).read())
        cipher_rsa = PKCS1_OAEP.new(private_key)
        session_key = cipher_rsa.decrypt(enc_session_key)
        cipher_aes = AES.new(session_key, AES.MODE_EAX, nonce=nonce)
        data = cipher_aes.decrypt_and_verify(ciphertext, tag)
    
        return data
    except Exception as e:
        print(f"Decryption failed: {e}")
    return None
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.