Session & Key Exchange                Pabba Sumanth
1. Implement Diffie-Hellman Algorithm and DH Key exchange   AP18110010172 CSE-C
   def power(a,b,P):
       if (b == 1):
           return a;
       else:
           return ((pow(a, b)) % P);
   P = int(input("Enter the prime number :"))
   print("The value of P :", P)
   G = int(input("Enter the primitve root for pervious prime number :"))
   print("The value of G :", G)
   a = int(input("Enter the chosen private key A :"))
   print("The private key a :", a)
   x = power(G, a, P)
   b = int(input("Enter the chosen private key B :"))
   print("The private key b :", b)
   y = power(G, b, P)
   ka = power(y, a, P)
   kb = power(x, b, P)
   print("Secret key for a is :", ka)
   print("Secret Key for b is :", kb)
  2. Encrypted communication over socket using AES
Server Code:
  import base64
  import hashlib
  import socket
  from Crypto import Random
  from Crypto.Cipher import AES
  class AESCipher(object):
      def __init__(self, key):
           self.bs = AES.block_size
           self.key = hashlib.sha256(key.encode()).digest()
      def encrypt(self, raw):
           raw = self._pad(raw)
           iv = Random.new().read(AES.block_size)
           cipher = AES.new(self.key, AES.MODE_CBC, iv)
           return base64.b64encode(iv + cipher.encrypt(raw.encode()))
      def decrypt(self, enc):
           enc = base64.b64decode(enc)
           iv = enc[:AES.block_size]
           cipher = AES.new(self.key, AES.MODE_CBC, iv)
          return
  self._unpad(cipher.decrypt(enc[AES.block_size:])).decode('utf-8')
    def _pad(self, s):
           return s + (self.bs - len(s) % self.bs) * chr(self.bs - len(s) %
self.bs)
    @staticmethod
    def _unpad(s):
           return s[:-ord(s[len(s)-1:])]
string="Pabba Sumanth"
password="djknBDS89dHFS(*HFSD())"
enc_string=str(AESCipher(password).encrypt(string))
enc_string_2=AESCipher(password).encrypt(string)
dec_string=str(AESCipher(password).decrypt(enc_string_2))
print("This is the password " + password)
print("Decrypted string: " + string)
print("Encrypted string: " + enc_string)
print("Decrypted string (v2): " + str(dec_string))
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(('10.0.2.15', 4444))
sock.listen(5)
print("Listening for connections...")
conn, addr = sock.accept()
conn.send(enc_string_2)
conn.close()
Client Code:
import socket
import base64
from Crypto import Random
from Crypto.Cipher import AES
import hashlib
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('10.0.2.15', 4444))
class AESCipher(object):
    def __init__(self, key):
        self.bs = AES.block_size
        self.key = hashlib.sha256(key.encode()).digest()
    def encrypt(self, raw):
        raw = self._pad(raw)
        iv = Random.new().read(AES.block_size)
        cipher = AES.new(self.key, AES.MODE_CBC, iv)
        return base64.b64encode(iv + cipher.encrypt(raw.encode()))
    def decrypt(self, enc):
        enc = base64.b64decode(enc)
        iv = enc[:AES.block_size]
           cipher = AES.new(self.key, AES.MODE_CBC, iv)
           return self._unpad(cipher.decrypt(enc[AES.block_size:])).decode('utf-
8')
      def _pad(self, s):
           return s + (self.bs - len(s) % self.bs) * chr(self.bs - len(s) %
self.bs)
      @staticmethod
      def _unpad(s):
           return s[:-ord(s[len(s)-1:])]
password="djknBDS89dHFS(*HFSD())"
data=sock.recv(4096)
decoded=AESCipher(password).decrypt(data.decode('utf-8'))
print(str(decoded))
sock.close()
Output:
Session Key establishment using RSA
Server code:
import socket
import math
from random import choice, randint
import itertools as it
if __name__ == '__main__':
   key=222
   svr = socket.socket()
   host = socket.gethostname()
   print("Server will start on host:", host)
   port = 5544
   svr.bind((host, port))
   print("Server is bound successfully")
   svr.listen(1)
   svr, addr = svr.accept()
   print(addr, "has connected")
   while 1:
         r_msg = svr.recv(1024).decode()
         print("\n*************** Message received *************")
         print('received message :', r_msg)
         k = r_msg.split('~')
         #print(k)
         session_key=int(k[1])
       print('request received from client and response is being sent to
client from for the session key ',session_key)
         rec_res=k[0]
       encrypted_text='response from server for
'+rec_res+'~'+str(session_key)
         print('sent message :', encrypted_text)
         svr.send(encrypted_text.encode())
#Client side code :
import random
import math
import socket
from collections import namedtuple
class RSA:
    def __init__(self):
         self.key = namedtuple("Key",["modulus","exponent"])
    def generateKeys(self):
   # two distinct prime numbers p and q
   p = self.__findPrime()
   q = self.__findPrime()
   # the modulus value
   n = p * q
   phi = (p - 1) * (q - 1)
   e = self.__findExponent(phi)
   d = self.__multiplicativeInverse(e,phi)
   publicKey = self.key(n,e)
   privateKey = self.key(n,d)
   return publicKey, privateKey
def encrypt(self,message,key):
   return self.__squareMultiply(message,key.exponent) % key.modulus
def decrypt(self,message,key):
   return self.__squareMultiply(message,key.exponent) % key.modulus
def __isPrime(self,n):
   # 2 and 3 are prime, 0 and 1 not
   if n <= 3:
       return n >= 2
   # easy check for 2 and 3
   if n % 2 == 0 or n % 3 == 0:
       return False
   # other numbers
   for i in range(5, int(math.sqrt(n)) + 1, 6):
       if n % i == 0 or n % (i + 2) == 0:
           return False
   return True
def __findPrime(self):
   # look for the first 10-bit prime
   n = random.randrange(1024)
   while(self.__isPrime(n) == False):
       n = random.randrange(1024)
   return n
def __gcd(self,a,b):
   temp = a
   # switch a for b so that
   # a is always greater b
   if b > a:
       a = b
       b = temp
   while(temp):
       temp = a % b
       a = b
       b = temp
   return a
def __findExponent(self,phi):
   e = random.randrange(2,phi)
   while(self.__gcd(phi,e) != 1):
       e = random.randrange(2,phi)
   return e
def __multiplicativeInverse(self,value,modulus):
   coef = 1
   coefDelay = 0
   valueDelay = modulus
   while(value):
       quotient = valueDelay//value
       valueDelay, value = value, valueDelay - quotient * value
       coefDelay, coef = coef, coefDelay - quotient * coef
   if coefDelay < 0:
       coefDelay += modulus
   return coefDelay
def __squareMultiply(self,base,power):
   if power < 0:
       raise ValueError("Negative powers not allowed")
   if power == 0:
       return 1
   if power == 1:
       return base
   # if power is odd, x_new = x * (x^2)^((n-1)/2)
   if power % 2:
       return base * self.__squareMultiply(base*base,(power-1)/2)
       # if power is even, x_new = (x^2)^(n/2)
       return self.__squareMultiply(base*base,power/2)
if __name__ == '__main__':
   s = socket.socket()
   host = 'DESKTOP-DVGT262'
   port = 5544
   try:
       s.connect((host, port))
       print("connected to server")
   except:
       print("connection to server is failed : (")
   rsa = RSA()
   public_key, private_key = rsa.generateKeys()
   session_key= random.randint(0, 200)
   while 1:
       raw_session_key = random.randint(0, 200)
       print("\n*****************************\n")
       msg = input("YOU:>> ")
       session_key=rsa.encrypt(raw_session_key,public_key)
       encrypted_text = msg + '~' + str(session_key)
       print('\ngenerated random session key : ',session_key)
       print("\nEncrypted message :", encrypted_text)
       s.send(encrypted_text.encode())
          r_msg = s.recv(1024).decode()
          print("\n*************** Message recieved *************")
          print('recieved message :',r_msg)
          k=r_msg.split('~')
          rec_sk=int(k[1])
          dec=rsa.decrypt(rec_sk, private_key)
          print('decoded session key using private key : ', dec )
          print('original session key :',raw_session_key)
          if(dec==raw_session_key):
              print('session key verified')
Output: