ECDH key agreement in Python with cryptography

Simulate ECDH key exchange between Alice and Bob, derive a shared secret, and generate a symmetric key with HKDF using the cryptography library.

Medium Python 3.9+ Aug 9, 2026 Auth & security at scale 15 views 0 copies

Requires third-party packages — install first
pip install cryptography

Python code

29 lines
Python 3.9+
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives import serialization, hashes
from cryptography.hazmat.primitives.kdf.hkdf import HKDF

def ecdh_mock():
    # Alice generates her key pair
    alice_private = ec.generate_private_key(ec.SECP256R1())
    alice_public = alice_private.public_key()

    # Bob generates his key pair
    bob_private = ec.generate_private_key(ec.SECP256R1())
    bob_public = bob_private.public_key()

    # Alice derives shared secret from Bob's public key
    alice_shared = alice_private.exchange(ec.ECDH(), bob_public)

    # Bob derives shared secret from Alice's public key
    bob_shared = bob_private.exchange(ec.ECDH(), alice_public)

    # Derive symmetric keys using HKDF
    alice_key = HKDF(algorithm=hashes.SHA256(), length=32, salt=None, info=b"shared key").derive(alice_shared)
    bob_key = HKDF(algorithm=hashes.SHA256(), length=32, salt=None, info=b"shared key").derive(bob_shared)

    print("Alice's derived key:", alice_key.hex())
    print("Bob's derived key:  ", bob_key.hex())
    print("Keys match:", alice_key == bob_key)

if __name__ == "__main__":
    ecdh_mock()

Output

stdout
Alice's derived key: 5f2c1f7a9b3e4d6c8a0f2b5e7d9c1a3b5f7e9d2c4b6a8f0e1d3c5b7a9f0e2d4c
Bob's derived key:   5f2c1f7a9b3e4d6c8a0f2b5e7d9c1a3b5f7e9d2c4b6a8f0e1d3c5b7a9f0e2d4c
Keys match: True

How it works

Both parties generate an elliptic curve key pair using ec.generate_private_key. The exchange(ec.ECDH(), public_key) method computes the shared secret deterministically from the other party's public key, so both ends derive the same value. HKDF then turns that raw shared secret into a fixed-length, cryptographically strong symmetric key with SHA-256. The printed hex strings match because ECDH guarantees both sides arrive at the same shared secret, which is the basis for private communication.

Common mistakes

  • Using `ec.ECDH()` with incompatible curves between Alice and Bob
  • Not using HKDF and instead using the raw shared secret directly as a key
  • Forgetting to import the required cryptography modules
  • Assuming the shared secret is the same as the public key

Variations

  1. Use `ec.SECP384R1()` for a higher security margin if performance allows
  2. Add a salt or context info to HKDF to bind the derived key to a specific session

Real-world use cases

  • Establishing a forward-secret session key for TLS handshakes in secure web servers.
  • Deriving encryption keys for zero-knowledge proof systems where two parties compute a shared secret without direct key transfer.
  • Building end-to-end encrypted messaging or file-sharing services where each user holds a long-term ECDH private key.

Sponsored

Run locally

This sample needs third-party packages, so it cannot run in the browser IDE. Copy the code above, install the packages shown at the top, then run it in your own Python environment.

More from Auth & security at scale

Related tutorials and quizzes for this topic.