import math
import os
import time
import hashlib
# 2048-bit Diffie-Helman function.
# Main DH parameters are defined in RFC5114:
# https://tools.ietf.org/html/rfc5114
# See chapter 2.3. "2048-bit MODP Group with 256-bit Prime Order Subgroup"
prime_hex = '87a8e61db4b6663cffbbd19c651959998ceef608660dd0f25d2ceed4435e3b00e00df8f1d61957d4faf7df4561b2aa3016c3d91134096faa3bf4296d830e9a7c209e0c6497517abd5a8a9d306bcf67ed91f9e6725b4758c022e0b1ef4275bf7b6c5bfc11d45f9088b941f54eb1e59bb8bc39a0bf12307f5c4fdb70c581b23f76b63acae1caa6b7902d52526735488a0ef13c6d9a51bfa4ab3ad8347796524d8ef6a167b5a41825d967e144e5140564251ccacb83e6b486f6b3ca3f7971506026c0b857f689962856ded4010abd0be621c3a3960a54e710c375f26375d7014103a4b54330c198af126116d2276e11715f693877fad7ef09cadb094ae91e1a1597'
generator_hex = '3fb32c9b73134d0b2e77506660edbd484ca7b18f21ef205407f4793a1a0ba12510dbc15077be463fff4fed4aac0bb555be3a6c1b0c6b47b1bc3773bf7e8c6f62901228f8c28cbb18a55ae31341000a650196f931c77a57f2ddf463e5e9ec144b777de62aaab8a8628ac376d282d6ed3864e67982428ebc831d14348f6f2f9193b5045af2767164e1dfc967c1fb3f2e55a4bd1bffe83b9c80d052b985d182ea0adb2a3b7313d3fe14c8484b1e052588b9b7d2bbd2df016199ecd06e1557cd0915b3353bbb64e0ec377fd028370df92b52c7891428cdc67eb6184b523d1db246c32f63078490f00ef8d647d148d47954515e2327cfef98c582664b4c0f6cc41659'
p = int(prime_hex, 16)
g = int(generator_hex, 16)
def private_to_public(a): # Converts secret key to public key; input - integer, output - raw byte string
A_int = pow(g, a, p)
A_hex = hex(A_int)[2:-1].zfill(512)
A = A_hex.decode('hex')
return A
def make_shared_secret(a, B): # Compute shared secret between public key B and secret key a, input - two integers, output - two raw byte strings
K_int = pow(B, a, p) # this is modulo exponentiation. In Python, don't use ((B ** a) % p), it will be terribly slow.
K_hex = hex(K_int)[2:-1].zfill(512) # Here we convert integer result of pow to hex string. zfill checks for size and adds zero if leading zeros are cut by hex()
K = K_hex.decode('hex') # Decoding hex. It is more convenient not to decode hex all the time, maybe you want to do .encode('base64')
return K # return result
def generate_keypair(): # Generate new DH keypair; input - none, output - two raw byte strings
rand = os.urandom(256) # Asking operating system for 256 random bytes.
prec_time = str(int(time.time() * 1000)) # Getting precise time in ms
sk_hex = hashlib.sha512(prec_time + rand).hexdigest() # Hashing those two together. Using hash function as mixer of entropy
sk_int = int(sk_hex, 16)
sk = sk_hex.decode('hex')
pk = private_to_public(sk_int)
return sk, pk
# ----------------------------------------------------------------------
# Uncomment numbered code blocks bellow, one by one, to see how it works
# ----------------------------------------------------------------------
# 1. Key generation, just as demo
#sec_raw, pub_raw = generate_keypair() # generate key pair using OS random source and precise time in ms (time added just in case)
#sechex = sec_raw.encode('hex')
#pubhex = pub_raw.encode('hex')
#print 'Private key: ', sechex # this prints keys in hexadecimal
#print 'Public key: ', pubhex
# 2. Convert given secret key to public key. Note that hex value is converted to integer with int(n, 16) function
#alice_secret_key = '4e9690615c755e286809f3dbd7ef6ef793553f9c754a6492c12a14d338e0b2be7914f2cd422c843b9900e200867b5dc0c7d2f9f6167a384c7071bb8673404fa6'
#alice_secret_key_integer = int(alice_secret_key, 16)
#alice_public_key = private_to_public(alice_secret_key_integer)
#print 'Public key: ', alice_public_key.encode('hex')
# 3.1 Alice side: Compute K (it is called shared secret), here we will use Alice secret and Bob's public key
#alice_secret_key = '4e9690615c755e286809f3dbd7ef6ef793553f9c754a6492c12a14d338e0b2be7914f2cd422c843b9900e200867b5dc0c7d2f9f6167a384c7071bb8673404fa6'
#alice_secret_key_integer = int(alice_secret_key, 16)
#bob_public_key_hex = '1ce10a6d81978a96bef66fe1a345c281680aaffbeea5bf4e3b00e02794ad21cb149c3681b3ede13bcc7fb56cbb10144a5ab5a236c65e24b858f4bdb8a74c0c315080fdd7e16ad8e0d0a2b7a068a6f75fd99a7c88db23dfde88fa2eb9fc1e66ea459bd96745832df6f019a41349e4e6b62d0c7b917a0e2a55156f209213419d35411d02e843aab2fbc2156e84cd9238bcc930698039a51a4c527a227b77cac32050dc2b6745cdfcdd794e47b96343bafea7a9feeeec5d649a23656661ab3187fbb2abfbfe04a74a94aa55554c1c28f21f8dda86e52596b357d1d8c62577872615e8b50ab78697be3c376c6f689cb1e06c42a9d72ae8464635c090a8b87243492c'
#bob_public_key_integer = int(bob_public_key_hex, 16)
#alices_K = make_shared_secret(alice_secret_key_integer, bob_public_key_integer)
#print alices_K.encode('hex')
# 3.2 Bob side: Compute K, but here we will use Bob's secret, and Alice public key
#bob_secret_key = 'dacea69a6f878114824d7f2f7ddac470b247d9d6f97fb837963aa714c07060a4771ad7edab288d305ad92e8f066064dfda825ea2688732bf251cd2b83c6624e7'
#bob_secret_key_integer = int(bob_secret_key, 16)
#alice_public_key = '07017050d4a00ab77db10c4a8f974ee9b2c887ed98daf282efbacdcf4f7a79fb7ef197f9565515782c16401d4a451e131f904e670ce74fcb1b2666abd72852c08e5c9fad6d750bcccfb7eb61a943e0c6061300371ecf243a559594499bd2189be12f62387ac0da7689dfc2e9433a1cc87c642be208d2e329e5e1c1dbb1db0e79617d5a3264fe2ca488c2b843c432e6aac7755258e8a7d46e638a97c65cca3fa5be61828d2a39967332205f65a75f011546012c868f76a3ad727539ff68a8e250a802e9fed8f660bd0abb5ce53bbf37c22ee78697daa18153357372d5acbcc885d309cdbcc0fac5bc158bd02d2eee40376a5f4aa3b1449834a4f3996275b4c677'
#alice_public_key_integer = int(alice_public_key, 16)
#bobs_K = make_shared_secret(bob_secret_key_integer, alice_public_key_integer)
#print bobs_K.encode('hex')