Clientlong-term RSA keysAttackerreads, drops, replaysServerlong-term RSA keys1 Session keys, signed with the long-term RSA keys2 Elliptic-curve DH keys, signed with the session keys3 Every message: new DH key, AES-encrypted text, signature, counterReplayed or droppedDetected, warning shown
How it works. Scroll sideways to see the whole diagram.

The problem

Send data from a client to a server through an attacker who can read, delete, and replay every packet, and still guarantee confidentiality, integrity, and that each side is talking to the other.

Key decisions

Long-term keys only vouch for new ones
The long-term RSA keys are used only to sign fresh session keys, which in turn sign an elliptic-curve Diffie-Hellman exchange. The attacker in the middle sees every key but can't forge one.
A new key for every message
Every message carries a new Diffie-Hellman public key, and the shared secret goes through a key-derivation function to become that message's AES key. Like the ratchet in Off-the-Record messaging, leaking one key exposes only one message.
Separate keys for separate jobs
Messages are encrypted with AES and signed with a different key, so breaking one doesn't give away the other.
Counters against replay
Every message carries a signed counter, so replayed, dropped, or reordered packets are detected and reported.

Results

  • Detects tampered, replayed, reordered, and dropped messages
  • Encryption and signing use separate keys

Built with

Python, PyCryptodome, AES, RSA, Elliptic-curve DH