text: #!/usr/bin/env python3
  import base64
  import json
  import secrets
  import socketserver
  from hashlib import sha256, sha1
  from Crypto.Cipher import AES
  from Crypto.Util.Padding import pad, unpad
  
  
  # SRP constants
  N = int('d4c7f8a2b32c11b8fba9581ec4ba4f1b04215642ef7355e37c0fc0443ef756ea2c6b8eeb755a1c723027663caa265ef785b8ff6a9b35227a52d86633dbdfca43', 16)
  k = int('b7867f1299da8cc24ab93e08986ebc4d6a478ad0', 16)
  g = 2
  
  
  def encrypt(key, message):
      message = json.dumps(message).encode()
      cipher = AES.new(key, AES.MODE_CBC)
      msg = cipher.encrypt(pad(message, AES.block_size))
      iv = cipher.iv
      hmac = sha1(sha1(key).digest() + msg + iv).digest()
      payload = {
          'message': base64.b64encode(msg).decode(),
          'iv': base64.b64encode(iv).decode(),
          'hmac': base64.b64encode(hmac).decode()
      }
      return payload
  
  
  def decrypt(key, message):
      msg = base64.b64decode(message['message'])
      iv = base64.b64decode(message['iv'])
      hmac = sha1(sha1(key).digest() + msg + iv).digest()
      if hmac != base64.b64decode(message['hmac']):
          return None
      cipher = AES.new(key, AES.MODE_CBC, iv)
      msg = unpad(cipher.decrypt(msg), AES.block_size)
      return json.loads(msg.decode())
  
  
  class SRPHandler(socketserver.StreamRequestHandler):
      timeout = 2
  
      def handle(self):
          # -----------------------------------------------------------------------
          # IDENTIFY TO SERVER
          # -----------------------------------------------------------------------
  
          payload = self.request.recv(1024).decode()
          payload = json.loads(payload)
  
          A = int(payload['A'], 16)
  
          # Generate password for administrator and log for side-channel SRP
          p = secrets.token_hex(32)
          print(p)
  
          # Generate session key
          s = secrets.token_hex(32)
          x = int(sha256((s + p).encode()).digest().hex(), 16)
          v = pow(g, x, N)
  
          # Calculate B
          b = int(secrets.token_hex(32), 16)
          B = (k * v) + pow(g, b, N)
          while B % N == 0:
              b = int(secrets.token_hex(32), 16)
              B = (k * v) + pow(g, b, N)
  
  
          # -----------------------------------------------------------------------
          # IDENTIFY TO CLIENT
          # -----------------------------------------------------------------------
  
          identify_to_client = { 's': s, 'B': f'{B:X}' }
          payload = json.dumps(identify_to_client)
          self.request.send(payload.encode())
  
          u = int(sha256(f'{A:X}{B:X}'.encode()).digest().hex(), 16)
          if u == 0:
              return
  
          S = pow(A * pow(v, u, N), b, N)
          M = sha256(f'{A:X}{B:X}{S:X}'.encode()).digest().hex()
  
          # -----------------------------------------------------------------------
          # PROOF TO SERVER
          # -----------------------------------------------------------------------
  
          payload = self.request.recv(1024).decode()
          payload = json.loads(payload)
          if payload['M'] != M:
              return
  
          # -----------------------------------------------------------------------
          # RETREVE SECRET
          # -----------------------------------------------------------------------
  
          payload = self.request.recv(1024).decode()
          key = sha256(f'{S:X}'.encode()).digest()
          payload = decrypt(key, json.loads(payload))
          if payload is None:
              return
  
          if payload['action'] == 'GetSecret':
              with open('flag.txt') as f:
                  payload = json.dumps(encrypt(key, json.dumps({ 'flag': f.read() })))
                  self.request.send(payload.encode())
  
  
  if __name__ == '__main__':
      socketserver.TCPServer.allow_reuse_address = True
      with socketserver.TCPServer(('0.0.0.0', 31337), SRPHandler) as server:
          server.serve_forever()
  
  