Hazmat X25519 using Curve 25519
[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 X25519, 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).
|
Theory
Curve 25519 is one of the most widely used ECC methods. It uses a curve of:
\(y^2 = x^3 + 486662 x^2 + x\)
This is a Montgomery curve. The prime number used is \(2^{255}-19\). 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)
Code
The code is:
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 from cryptography.hazmat.backends import default_backend import binascii import sys size=32 # 256 bit key if (len(sys.argv)>1): size=int(sys.argv[1]) Bob_private_key = X25519PrivateKey.generate() Alice_private_key = X25519PrivateKey.generate() Bob_shared_key = Bob_private_key.exchange(Alice_private_key.public_key()) Bob_derived_key = HKDF(algorithm=hashes.SHA256(),length=size,salt=None,info=b'',backend=default_backend()).derive(Bob_shared_key) Alice_shared_key = Alice_private_key.exchange(Bob_private_key.public_key()) Alice_derived_key = HKDF(algorithm=hashes.SHA256(),length=size,salt=None,info=b'',backend=default_backend()).derive(Alice_shared_key) print ("Name of curve: Curve 25519") vals = binascii.b2a_hex(Bob_private_key.private_bytes(serialization.Encoding.Raw,serialization.PrivateFormat.Raw,serialization.NoEncryption())) print (f"\nBob private key value: {vals.decode()}") vals=Bob_private_key.public_key() enc_point=binascii.b2a_hex(vals.public_bytes(encoding=serialization.Encoding.DER,format=serialization.PublicFormat.SubjectPublicKeyInfo)).decode() print("Bob's public key (DER): ",enc_point) vals = binascii.b2a_hex(Alice_private_key.private_bytes(serialization.Encoding.Raw,serialization.PrivateFormat.Raw,serialization.NoEncryption())) print (f"\nAlice private key value: {vals.decode()}") vals=Alice_private_key.public_key() enc_point=binascii.b2a_hex(vals.public_bytes(encoding=serialization.Encoding.DER,format=serialization.PublicFormat.SubjectPublicKeyInfo)).decode() print("Alice's public key (DER): ",enc_point) print ("\nBob's derived key: ",binascii.b2a_hex(Bob_derived_key).decode()) print("Alice's derived key: ",binascii.b2a_hex(Alice_derived_key).decode()) print("\n\n\n== Additional (PEM) ==") vals = Bob_private_key.private_bytes(serialization.Encoding.PEM,serialization.PrivateFormat.PKCS8,serialization.NoEncryption()) print (f"\nBob private key value (PEM):\n{vals.decode()}") vals=Bob_private_key.public_key() enc_point=vals.public_bytes(encoding=serialization.Encoding.PEM,format=serialization.PublicFormat.SubjectPublicKeyInfo).decode() print("Bob's public key (PEM):\n",enc_point) vals = Alice_private_key.private_bytes(serialization.Encoding.PEM,serialization.PrivateFormat.PKCS8,serialization.NoEncryption()) print (f"\nAlice private key value (PEM):\n{vals.decode()}") vals=Alice_private_key.public_key() enc_point=vals.public_bytes(encoding=serialization.Encoding.PEM,format=serialization.PublicFormat.SubjectPublicKeyInfo).decode() print("Alice's public key (PEM):\n",enc_point)
A sample run is:
Name of curve: Curve 25519 Bob private key value: b'302db48a210050cee1321a3cf6821b63082d7527852c461c39858d3188963c47' Bob's public key: 302a300506032b656e032100d05a09203918e1447cf3677ad329d1a66d58ea849a38f011b753c4432ee0ef54 Alice private key value: b'10177e5d087d1a4c13e703021d9d7e1745f32c287bdff9b5f8f329775512547f' Alice's public key: 302a300506032b656e032100e70bd59e038ccea1d164ffa25ee53de5d661bdf12dcc98626da1cbfdc0479f7e Bob's derived key: 6801774d9090d788d76d892a5f2a005b95c2ae7e0ef829e6c696497383202837 Alice's derived key: 6801774d9090d788d76d892a5f2a005b95c2ae7e0ef829e6c696497383202837
With Curve 25519 we only need the x-axis value, so that public keys are smallers than with ECDH. If we try the DER value of "302a300506032b656e032100e70bd59e038ccea1d164ffa25ee53de5d661bdf12dcc98626da1cbfdc0479f7e":
DER: 302a300506032b656e032100e70bd59e038ccea1d164ffa25ee53de5d661bdf12dcc98626da1cbfdc0479f7e [U] SEQUENCE (30) [U] SEQUENCE (30) [U] OBJECT (06): 1.3.101.110 [U] BIT STRING (03): 0xb'00E70BD59E038CCEA1D164FFA25EE53DE5D661BDF12DCC98626DA1CBFDC0479F7E' Public key (0bd59e038ccea1d164ffa25ee53de, 5d661bdf12dcc98626da1cbfdc0479f7e) -----BEGIN PUBLIC KEY----- MCowBQYDK2VuAyEA5wvVngOMzqHRZP+iXuU95dZhvfEtzJhibaHL/cBHn34= -----END PUBLIC KEY-----