Hazmat ECDHIn the Diffie-Hellman (DH) key exchange method, we have a base of \(g\) and a shared prime number of \(p\), and where Bob generates a random value of \(b\) and Alice generates a random value of \(a\). Bob sends \(B=g^b \pmod p\) to Alice, and Alice sends \(A=g^a \pmod p\) to Bob. Alice then generates the shared key of \(B^a \pmod p\) and Bob generates the same shared key of \(A^b \pmod p\). The shared key is actually \(g^{ab} \pmod p\). With ECDH (Elliptic Curve Diffie Hellman) Bob generates a random value of \(b\) and Alice generates a random value of \(a\). Bob then sends Alice the public key point of \(B=bG\) and Alice sends Bob the point key point of \(A=aG\), and where \(G\) is the base point on the curve. Bob then computes \(bA\) and Alice computes \(aB\). They should get the same point and which is \(abG\) [article]. |
Outline
In the Diffie-Hellman (DH) key exchange method, we have a base of \(g\) and a shared prime number of \(p\), and where Bob generates a random value of \(b\) and Alice generates a random value of \(a\). Bob sends:
\(B=g^b \pmod p\)
to Alice, and Alice sends:
\(A=g^a \pmod p\)
to Bob. Alice then generates the shared key of:
\(B^a \pmod p\)
and Bob generates the same shared key of:
\(A^b \pmod p\)
The shared key is actually:
\(g^{ab} \pmod p\)
With ECDH (Elliptic Curve Diffie Hellman), Bob generates a random value of \(b\) and Alice generates a random value of \(a\). Bob then sends Alice the public key point of:
\(B=bG\)
and Alice sends Bob the point key point of:
\(A=aG\)
and where \(G\) is the base point on the curve. Bob then computes:
\(bA\)
and Alice computes:
\(aB\)
They should get the same point and which is:
\(abG\)
Bob and Alice can then use this shared secret with a HKDF (HMAC Key Derivation Function) to generate the shared key. An outline of the process is (using dA and dB as the private keys for Alice and Bob, respectively):
And here is an outline of these methods:
Code
In the sample run, we see, in this case, that Bob and Alice create a 256-bit secret value (their private key) and then generate a 512-bit public key point. The public key points are exchanged, and then the multiply the point they received with their private key value, and the should have the same shared value. Next we feed this shared value into a key derivation function (KDF) such as HKDF, and they will generate the same shared encryption key. This key is often used with a symmetric encryption method, such as for AES 128-bit or AES 256-bit:
from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.primitives.kdf.hkdf import HKDF import binascii import sys Bob_private_key = ec.generate_private_key(ec.SECP384R1()) Alice_private_key = ec.generate_private_key(ec.SECP384R1()) size=32 # 256 bit key if (len(sys.argv)>1): type=int(sys.argv[1]) if (len(sys.argv)>2): size=int(sys.argv[2]) if (type==1): Bob_private_key = ec.generate_private_key(ec.SECP192R1()) Alice_private_key = ec.generate_private_key(ec.SECP192R1()) elif (type==2): Bob_private_key = ec.generate_private_key(ec.SECP224R1()) Alice_private_key = ec.generate_private_key(ec.SECP224R1()) elif (type==3): Bob_private_key = ec.generate_private_key(ec.SECP256K1()) Alice_private_key = ec.generate_private_key(ec.SECP256K1()) elif (type==4): Bob_private_key = ec.generate_private_key(ec.SECP256R1()) Alice_private_key = ec.generate_private_key(ec.SECP256R1()) elif (type==5): Bob_private_key = ec.generate_private_key(ec.SECP384R1()) Alice_private_key = ec.generate_private_key(ec.SECP384R1()) elif (type==6): Bob_private_key = ec.generate_private_key(ec.SECP521R1()) Alice_private_key = ec.generate_private_key(ec.SECP521R1()) elif (type==7): Bob_private_key = ec.generate_private_key(ec.BrainpoolP256R1()) Alice_private_key = ec.generate_private_key(ec.BrainpoolP256R1()) elif (type==8): Bob_private_key = ec.generate_private_key(ec.BrainpoolP384R1()) Alice_private_key = ec.generate_private_key(ec.BrainpoolP384R1()) elif (type==9): Bob_private_key = ec.generate_private_key(ec.BrainpoolP512R1()) Alice_private_key = ec.generate_private_key(ec.BrainpoolP512R1()) Bob_shared_key = Bob_private_key.exchange(ec.ECDH(), Alice_private_key.public_key()) Bob_derived_key = HKDF(algorithm=hashes.SHA256(),length=size,salt=None,info=b'',).derive(Bob_shared_key) Alice_shared_key = Alice_private_key.exchange(ec.ECDH(), Bob_private_key.public_key()) Alice_derived_key = HKDF(algorithm=hashes.SHA256(),length=size,salt=None,info=b'',).derive(Alice_shared_key) print ("Name of curve: ",Bob_private_key.public_key().curve.name) print (f"Generated key size: {size} bytes ({size*8} bits)") vals = Bob_private_key.private_numbers() print (f"\nBob private key value: {vals.private_value}") vals=Bob_private_key.public_key().public_numbers() enc_point=binascii.b2a_hex(vals.encode_point()).decode() print("Bob's public key: ",enc_point) vals = Alice_private_key.private_numbers() print (f"\nAlice private key value: {vals.private_value}") vals=Alice_private_key.public_key().public_numbers() enc_point=binascii.b2a_hex(vals.encode_point()).decode() print("Alice's public key: ",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())
A sample run is:
Name of curve: secp521r1 Generated key size: 32 bytes (256 bits) Bob private key value: 3680820456027711443111164432843447368856697859743326998743942149697526087458219258919378678502536008736802984899594567754710518459992586097203945148934450532 Bob's public key: 0401312468c2545bb4a33504ac965f9c234eb65dbc77bd306f6f82a65c03438f8a90933f54558cb54e5f6859ffb06eac14b0e8d7e4f862b554bfe0823e71276a007df8001e56193c341954a9a170fd83e74f48f4263d755b8c8def670d362576f9337c1d80130e99042e852a96336e553911f995adb3d833fce1412952ccb9c1236c270a13 Alice private key value: 2351846976615995221613324575122431785712179957813023727849676138460840229905591998842409630221590167929266974417834116420299522765060849372316389219092012349 Alice's public key: 04000674bfc814628bee0714565ca2b7ccac352cefc28e68c64e20962522b45c2313d8389577ab741676e7bb60d8d415a4525e5fdd172c8a92f803901d89f796dc39b501ee0471d3ff3ad0793fe07b23612724ed143357ad563c3301439c509f0e799300e63ea42b1cb25a85fe24255f0c30d61e184089fb317deec1c8537c642dfff5507c Bob's derived key: d816dbb01a2aeefa35e07d864d8399114d35fc2ad1e532bcc0adbcf23cef5959 Alice's derived key: d816dbb01a2aeefa35e07d864d8399114d35fc2ad1e532bcc0adbcf23cef5959