Hazmat X25519 key exchange
[Hazmat Home][Home]
Curve 25519 is one of the most widely used ECC methods. It uses a curve of \(y^2 = x^3 + 486662 x^2 + x\) [plot], and which is a Montgomery curve. The prime number used is \(2^{255}-19\). This page implements ECDH, and which is the method used in Tor to exchange the key. In this case we will use Python to implement X25519 (and which uses Curve 25519), but only uses the x-axis point for the sharing of values. The base point \(G\) on Curve 25519 is (9,1478161944 ... 7755586237401)[here] and the paramaters based by on RFC 7748 [here].
|
X2519 and ECDH
We must thus create a unique encryption key for each routing host. This is often achieved by using X25519, and uses ECDH (Elliptic Curve Diffie Hellman). With this we select a base x co-ordinate point of \(G\), and then Bob and Alice generate random values, and determine their public keys. Alice generates \(a\), and Bob generates \(b\). Alice’s public key will be:
\(A= aG \)
and Bob’s public key becomes:
\(B=bG \)
The exchange their values, and Alice multiplies by the value received from Bob by \(a\), and Bob multiplies the value he receives from Alice by \(b\). They should then end up with the same value, and which should be:
\(K= abG \)
For the shared key we only concentrate on the x-co-ordinate of \(K\), and then use a KDF (Key Derivation Function) to generate the derived key. Normally we use HKDF (HMAC KDF) to convert the shared key into a derived key.
Code
from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey from cryptography.hazmat.primitives.kdf.hkdf import HKDF from cryptography.hazmat.primitives import serialization import binascii import sys size=32 if (len(sys.argv)>1): size=int(sys.argv[1]) alice_private_key = X25519PrivateKey.generate() alice_public_key = alice_private_key.public_key() bob_private_key = X25519PrivateKey.generate() bob_public_key = bob_private_key.public_key() shared_key = alice_private_key.exchange(bob_public_key) derived_key = HKDF(algorithm=hashes.SHA256(),length=size,salt=None,info=b'test data',).derive(shared_key) print ("Shared key: ",binascii.b2a_hex(shared_key)) print ("\nDerived key: ",binascii.b2a_hex(derived_key)) pem = alice_private_key.private_bytes(encoding=serialization.Encoding.PEM,format=serialization.PrivateFormat.PKCS8,encryption_algorithm=serialization.NoEncryption()) print ("\nAlice private key",pem.decode()) pem = alice_public_key.public_bytes(encoding=serialization.Encoding.PEM,format=serialization.PublicFormat.SubjectPublicKeyInfo) print ("\nAlice Public key (PEM):\n",pem.decode()) pem = bob_private_key.private_bytes(encoding=serialization.Encoding.PEM,format=serialization.PrivateFormat.PKCS8,encryption_algorithm=serialization.NoEncryption()) print ("Bob private key",pem.decode()) pem = bob_public_key.public_bytes(encoding=serialization.Encoding.PEM,format=serialization.PublicFormat.SubjectPublicKeyInfo) print ("\nBob Public key (PEM):\n",pem.decode())
A sample run is:
Shared key: b'848a6c41d5d7222efd3f2a831297536b5f8cc60db643f90b65689ba81d41c90b' Derived key: b'5fc8bf181ad4faf3636bdf8e5e4f5def114e28bc68dc56aa4c1cac9071906eb5' Alice private key -----BEGIN PRIVATE KEY----- MC4CAQAwBQYDK2VuBCIEIPiWH8Wl+KftQnB5/30Yhp9Yr8KnFZDYUq9pmXk5TNFx -----END PRIVATE KEY----- Alice Public key (PEM): -----BEGIN PUBLIC KEY----- MCowBQYDK2VuAyEAuUV48nMrlzxXjq3OLOhsTIjV/b8ux5gevURcINFu5jY= -----END PUBLIC KEY----- Bob private key -----BEGIN PRIVATE KEY----- MC4CAQAwBQYDK2VuBCIEIBBBFvHnddHJ9DytEPgsXrccEl7xc9kRqqMfcdJF8Kps -----END PRIVATE KEY----- Bob Public key (PEM): -----BEGIN PUBLIC KEY----- MCowBQYDK2VuAyEAb9Tz79bubJHpFmul2Nn/RgxbrBu7SjaiIy4eIMrOBmU= -----END PUBLIC KEY-----