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.
pip install cryptography
Python code
29 linesfrom 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
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
- Use `ec.SECP384R1()` for a higher security margin if performance allows
- 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
More from Auth & security at scale
- ACME LetsEncrypt Mock Challenge Server in Python medium
- AES GCM encryption and decryption in Python medium
- Build a Mock OIDC Userinfo Endpoint in Python with Flask easy
- ChaCha20-Poly1305 mock in Python medium
- Enforce TLS 1.2 Minimum in Python easy
- Fetch Secrets from a Mock Secrets Manager in Python easy
Keep learning
Related tutorials and quizzes for this topic.