Hazmat ECDH
[Hazmat Home][Home]
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\) [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 from cryptography.hazmat.primitives import serialization from cryptography.hazmat.backends import default_backend import binascii import sys Bob_private_key = ec.generate_private_key(ec.SECP384R1(),default_backend()) Alice_private_key = ec.generate_private_key(ec.SECP384R1(),default_backend()) 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(),default_backend()) Alice_private_key = ec.generate_private_key(ec.SECP192R1(),default_backend()) elif (type==2): Bob_private_key = ec.generate_private_key(ec.SECP224R1(),default_backend()) Alice_private_key = ec.generate_private_key(ec.SECP224R1(),default_backend()) elif (type==3): Bob_private_key = ec.generate_private_key(ec.SECP256K1(),default_backend()) Alice_private_key = ec.generate_private_key(ec.SECP256K1(),default_backend()) elif (type==4): Bob_private_key = ec.generate_private_key(ec.SECP256R1(),default_backend()) Alice_private_key = ec.generate_private_key(ec.SECP256R1(),default_backend()) elif (type==5): Bob_private_key = ec.generate_private_key(ec.SECP384R1(),default_backend()) Alice_private_key = ec.generate_private_key(ec.SECP384R1(),default_backend()) elif (type==6): Bob_private_key = ec.generate_private_key(ec.SECP521R1(),default_backend()) Alice_private_key = ec.generate_private_key(ec.SECP521R1(),default_backend()) elif (type==7): Bob_private_key = ec.generate_private_key(ec.BrainpoolP256R1(),default_backend()) Alice_private_key = ec.generate_private_key(ec.BrainpoolP256R1(),default_backend()) elif (type==8): Bob_private_key = ec.generate_private_key(ec.BrainpoolP384R1(),default_backend()) Alice_private_key = ec.generate_private_key(ec.BrainpoolP384R1(),default_backend()) elif (type==9): Bob_private_key = ec.generate_private_key(ec.BrainpoolP512R1(),default_backend()) Alice_private_key = ec.generate_private_key(ec.BrainpoolP512R1(),default_backend()) 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'',backend=default_backend()).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'',backend=default_backend()).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() enc_point=binascii.b2a_hex(vals.public_bytes(encoding=serialization.Encoding.DER,format=serialization.PublicFormat.SubjectPublicKeyInfo)).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() enc_point=binascii.b2a_hex(vals.public_bytes(encoding=serialization.Encoding.DER,format=serialization.PublicFormat.SubjectPublicKeyInfo)).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()) 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) 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.OpenSSH,format=serialization.PublicFormat.OpenSSH).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.OpenSSH,format=serialization.PublicFormat.OpenSSH).decode() print("Alice's public key (PEM):\n",enc_point)
A sample run is:
Name of curve: secp192r1 Generated key size: 32 bytes (256 bits) Bob private key value: 4565128601158293398868221410108459972405670741172984810291 Bob's public key: 3049301306072a8648ce3d020106082a8648ce3d03010103320004ec873f8bf81c9985d516c438ea15a672442e8e4bbe11c6544b017e47d873f050d4f8dce0c6a800d547ca4d600929faac Alice private key value: 5847303574743559517911461610969278556811374406189624555408 Alice's public key: 3049301306072a8648ce3d020106082a8648ce3d03010103320004fa3c725bb35ead9c995711298151b6f958c7f00f350ec2d9e3827543ee6da53115b0d23349915d5600a7e6c365774f88 Bob's derived key: 4fa02a73756e5c6e94279c2bc7bea9d3c8fd7c14ba4a2efc655c00686d7c60b2 Alice's derived key: 4fa02a73756e5c6e94279c2bc7bea9d3c8fd7c14ba4a2efc655c00686d7c60b2 == Additional (PEM) == Bob private key value (PEM): -----BEGIN PRIVATE KEY----- MG8CAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQEEVTBTAgEBBBi6LiqfSQ1W7Ymx1haI aS9OnA1y2iuxCzOhNAMyAATshz+L+ByZhdUWxDjqFaZyRC6OS74RxlRLAX5H2HPw UNT43ODGqADVR8pNYAkp+qw= -----END PRIVATE KEY----- Bob's public key (PEM): -----BEGIN PUBLIC KEY----- MEkwEwYHKoZIzj0CAQYIKoZIzj0DAQEDMgAE7Ic/i/gcmYXVFsQ46hWmckQujku+ EcZUSwF+R9hz8FDU+NzgxqgA1UfKTWAJKfqs -----END PUBLIC KEY----- Alice private key value (PEM): -----BEGIN PRIVATE KEY----- MG8CAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQEEVTBTAgEBBBjueLKkziU4qIP5+xFS Ui5gZNIdimmTd5ChNAMyAAT6PHJbs16tnJlXESmBUbb5WMfwDzUOwtnjgnVD7m2l MRWw0jNJkV1WAKfmw2V3T4g= -----END PRIVATE KEY----- Alice's public key (PEM): -----BEGIN PUBLIC KEY----- MEkwEwYHKoZIzj0CAQYIKoZIzj0DAQEDMgAE+jxyW7NerZyZVxEpgVG2+VjH8A81 DsLZ44J1Q+5tpTEVsNIzSZFdVgCn5sNld0+I -----END PUBLIC KEY-----