}
$dh = new DH();
print "Testing normal comms:\n\n";
$A = new ConversationEntity('A', $dh);
$B = new ConversationEntity('B', $dh);
$A->onSend = [$B, 'receive'];
$B->onSend = [$A, 'receive'];
$A->kexRequest();
$A->send('Hello there!');
$B->send('Hi!');
print "\nSetting up MITM:\n\n";
$state = 0;
$stolenP = null;
$evilShared = null;
$A = new ConversationEntity('A', $dh);
$B = new ConversationEntity('B', $dh);
$A->onSend = function ($data) use($B, &$state, &$stolenP, &$evilShared, $dh) {
    if ($state === 0) {
        print "M: Manipulating kex req\n";
        $obj = json_decode($data);
        $obj->A = $obj->p;
        $stolenP = gmp_init($obj->p, 16);
        $evilShared = gmp_strval($dh->generateShared($stolenP, $stolenP), 16);
        $state = 1;
        $B->receive(json_encode($obj));
    } else {
        $key = sha1($evilShared, true);
        $iv = substr($data, 0, 16);
        $message = decryptAES128CBC(substr($data, 16), $key, $iv);
        print "M: sniffed: {$message}\n";
    }
 function __construct(ConversationEntity $A, ConversationEntity $B)
 {
     $A->onSend = function ($data) use($B) {
         $B->receive($this->sniffData($data));
     };
     $B->onSend = function ($data) use($A) {
         $A->receive($this->sniffData($data));
     };
 }