It combines both
- AES (symmetric) - encrypts the actual message
- RSA (Asymmetric) - encrypts the AES key (secure exchange) RSA is secure but slow, while AES is fast but it requires a shared key
Randomly generated for each message must remain secret.
Random for each encryption Ensures to produce different ciphertexts for repeated messages Not secret, must be shared with the receiver
- Public Key - encrypt AES key (anyone can use it)
- Private key - decrypt AES key (must be kept secret)
Data is sent as bytes may need chunking for large messages
- socket.bind() -> where server listens
- socket.listen() -> starts listening for connections
- socket.accept() -> accepts incoming connections
- socket.connect() -> client connects to the server Networking basics are simple: server listens, client connects and data flows Both sides (sender & receiver) must use UTF-8 or byte encoding.
Python objects can't be sent raw over a network.
- pickle.dumps() -> serialize tuple (encrypted_key, iv, encrypted_message)
- pickle.loads() -> deserialize on the other side Always package all parts together, receiver unpacks them
It makes AES work like a stream cipher (can encrypt data of any length).
- It encrypts the previous ciphertext block (or IV for the first one) to create a keystream
- The keystream is then XORed with the (first or next block in the sequence of) plaintext to produce ciphertext.
- Each cipher text block depends on the one before it
No padding needed, errors affect only one block, repeated messages look different (because of IV and chaining)
Secure, flexible, and produces unique ciphertexts even for identical plaintexts.
1st Bloack:
- AES(IV) = keystream_1
- Ciphertext_1 = Plaintext_1 XOR keystream_1
Next Block:
- AES(Ciphertext_1) = keystream_2
- Ciphertext_2 = Plaintext_2 XOR keystream_2
Generate RSA key pair:
- Public Key -> public_key.pem
- Private Key -> private_key.pem Done once per user/server
- Loads the public key of the receiver
- Prepare message -> converts to bytes
- Generates AES key + IV
- Encrypts message using AES in CFB mode:
- cipher = Cipher(algorithms.AES(aes_key), modes.CFB(iv))
- encrypted_message = encryptor.update(message) + encryptor.finalize()
- Encrypt AES key with recipient's RSA public key
- Package (encrypted_key, IV, encrypted_message) -> send via TCP socket.
- Receives data -> unpacks (encrypted_key, IV, encrypted_message)
- Decrypts AES key using its RSA private key
- Decrypts message using AES + IV:
- cipher = Cipher(algorithms.AES(aes_key), modes.CFB(iv))
- message = decryptor.update(encrypted_message) + decryptor.finalize()
- RSA -> key exchange
- AES -> data encryption
- IV -> randomness
- CFB -> feedback chaining
- Socket -> data transfer
- Pickle -> packaging all parts together
- plaintext -> AES encrypt -> ciphertext -> send
- AES key -> RSA encrypt -> send
- Receive -> RSA decrypt AES key -> AES decrypt ciphertext -> plaintext