Example #1
0
class OTREncryption(object):
    def __init__(self, stream):
        self.stream = stream
        self.otr_cache = OTRCache()
        self.otr_session = OTRSession(
            self.otr_cache.private_key, self.stream, supported_versions={
                3
            })  # we need at least OTR-v3 for question based SMP

        notification_center = NotificationCenter()
        notification_center.add_observer(self, sender=stream)
        notification_center.add_observer(self, sender=self.otr_session)

    @property
    def active(self):
        try:
            return self.otr_session.encrypted
        except AttributeError:
            return False

    @property
    def cipher(self):
        return 'AES-128-CTR' if self.active else None

    @property
    def key_fingerprint(self):
        try:
            return binascii.hexlify(self.otr_session.local_private_key.
                                    public_key.fingerprint).decode()
        except (AttributeError, TypeError):
            return None

    @property
    def peer_fingerprint(self):
        try:
            return binascii.hexlify(
                self.otr_session.remote_public_key.fingerprint).decode()
        except (AttributeError, TypeError):
            return None

    @property
    def peer_name(self):
        try:
            return self.__dict__['peer_name']
        except KeyError:
            trusted_peer = self.otr_cache.trusted_peers.get(
                self.peer_fingerprint, None)
            if trusted_peer is None:
                return ''
            else:
                return self.__dict__.setdefault('peer_name',
                                                trusted_peer.description)

    @peer_name.setter
    def peer_name(self, name):
        old_name = self.peer_name
        new_name = self.__dict__['peer_name'] = name
        if old_name != new_name:
            trusted_peer = self.otr_cache.trusted_peers.get(
                self.peer_fingerprint, None)
            if trusted_peer is not None:
                trusted_peer.description = new_name
                self.otr_cache.save()
            notification_center = NotificationCenter()
            notification_center.post_notification(
                "ChatStreamOTRPeerNameChanged",
                sender=self.stream,
                data=NotificationData(name=name))

    @property
    def verified(self):
        return self.peer_fingerprint in self.otr_cache.trusted_peers

    @verified.setter
    def verified(self, value):
        peer_fingerprint = self.peer_fingerprint
        old_verified = peer_fingerprint in self.otr_cache.trusted_peers
        new_verified = bool(value)
        if peer_fingerprint is None or new_verified == old_verified:
            return
        if new_verified:
            self.otr_cache.trusted_peers.add(
                OTRTrustedPeer(peer_fingerprint, description=self.peer_name))
        else:
            self.otr_cache.trusted_peers.remove(peer_fingerprint)
        self.otr_cache.save()
        notification_center = NotificationCenter()
        notification_center.post_notification(
            "ChatStreamOTRVerifiedStateChanged",
            sender=self.stream,
            data=NotificationData(verified=new_verified))

    @run_in_twisted_thread
    def start(self):
        if self.otr_session is not None:
            self.otr_session.start()

    @run_in_twisted_thread
    def stop(self):
        if self.otr_session is not None:
            self.otr_session.stop()

    @run_in_twisted_thread
    def smp_verify(self, secret, question=None):
        self.otr_session.smp_verify(secret, question)

    @run_in_twisted_thread
    def smp_answer(self, secret):
        self.otr_session.smp_answer(secret)

    @run_in_twisted_thread
    def smp_abort(self):
        self.otr_session.smp_abort()

    def handle_notification(self, notification):
        handler = getattr(self, '_NH_%s' % notification.name, Null)
        handler(notification)

    def _NH_MediaStreamDidStart(self, notification):
        if self.stream.start_otr:
            self.otr_session.start()

    def _NH_MediaStreamDidEnd(self, notification):
        notification.center.remove_observer(self, sender=self.stream)
        notification.center.remove_observer(self, sender=self.otr_session)
        self.otr_session.stop()
        self.otr_session = None
        self.stream = None

    _NH_MediaStreamDidNotInitialize = _NH_MediaStreamDidEnd

    def _NH_OTRSessionStateChanged(self, notification):
        notification.center.post_notification(
            'ChatStreamOTREncryptionStateChanged',
            sender=self.stream,
            data=notification.data)

    def _NH_OTRSessionSMPVerificationDidStart(self, notification):
        notification.center.post_notification(
            'ChatStreamSMPVerificationDidStart',
            sender=self.stream,
            data=notification.data)

    def _NH_OTRSessionSMPVerificationDidNotStart(self, notification):
        notification.center.post_notification(
            'ChatStreamSMPVerificationDidNotStart',
            sender=self.stream,
            data=notification.data)

    def _NH_OTRSessionSMPVerificationDidEnd(self, notification):
        notification.center.post_notification(
            'ChatStreamSMPVerificationDidEnd',
            sender=self.stream,
            data=notification.data)
Example #2
0
class DataConnection(object):
    implements(IObserver)

    def __init__(self, name):
        self.name = name
        self.secret = None
        self.private_key = DSAPrivateKey.generate()
        self.otr_session = OTRSession(self.private_key, transport=self)
        self.peer = None
        self.send_queue = EventQueue(handler=self._send_handler)
        self.send_queue.start()
        self.ake_done = Event()
        self.smp_done = Event()
        self.all_done = Event()
        self.otr_done = Event()
        self.smp_status = None
        self.same_secrets = None
        self.sent_message = None
        self.received_message = None
        NotificationCenter().add_observer(self, sender=self.otr_session)

    def _send_handler(self, message):
        time.sleep(0.01)
        self.peer.receive(message)

    def connect(self, peer):
        self.peer = peer

    def disconnect(self):
        self.send_queue.stop()
        self.send_queue = None

    def start_otr(self, secret=None):
        self.secret = secret
        self.otr_session.start()

    def stop_otr(self):
        self.otr_session.stop()

    def inject_otr_message(self, message):
        log.debug("{0.name} sending: {1!r}".format(self, message))
        self.send_queue.put(message)

    def send(self, content, content_type='text/plain'):
        log.debug("{0.name} encoding: {1!r}".format(self, content))
        self.sent_message = content
        content = self.otr_session.handle_output(content, content_type)
        log.debug("{0.name} sending: {1!r}".format(self, content))
        self.send_queue.put(content)

    def receive(self, message):
        # log.debug("{0.name} received: {1!r}".format(self, message))
        try:
            message = self.otr_session.handle_input(message, 'text/plain')
        except IgnoreMessage:
            return
        else:
            log.debug("{0.name} decoded:  {1!r}".format(self, message))
            self.received_message = message
            self.all_done.set()

    def handle_notification(self, notification):
        handler = getattr(self, '_NH_{0.name}'.format(notification), Null)
        handler(notification)

    def _NH_OTRSessionStateChanged(self, notification):
        if notification.data.new_state is OTRState.Encrypted:
            self.ake_done.set()
            if self.secret is None:
                self.smp_done.set()
            elif self.name < self.peer.name:
                self.otr_session.smp_verify(secret=self.secret)
        elif notification.data.old_state is OTRState.Encrypted:
            self.otr_done.set()

    def _NH_OTRSessionSMPVerificationDidStart(self, notification):
        if notification.data.originator == 'remote':
            if self.secret:
                self.otr_session.smp_answer(secret=self.secret)
            else:
                self.otr_session.smp_abort()

    def _NH_OTRSessionSMPVerificationDidNotStart(self, notification):
        self.smp_status = notification.data.reason
        self.smp_done.set()

    def _NH_OTRSessionSMPVerificationDidEnd(self, notification):
        self.same_secrets = notification.data.same_secrets
        self.smp_status = notification.data.status
        self.smp_done.set()
Example #3
0
class DataConnection(object):
    implements(IObserver)

    def __init__(self, name):
        self.name = name
        self.secret = None
        self.private_key = DSAPrivateKey.generate()
        self.otr_session = OTRSession(self.private_key, transport=self)
        self.peer = None
        self.send_queue = EventQueue(handler=self._send_handler)
        self.send_queue.start()
        self.ake_done = Event()
        self.smp_done = Event()
        self.all_done = Event()
        self.otr_done = Event()
        self.smp_status = None
        self.same_secrets = None
        self.sent_message = None
        self.received_message = None
        NotificationCenter().add_observer(self, sender=self.otr_session)

    def _send_handler(self, message):
        time.sleep(0.01)
        self.peer.receive(message)

    def connect(self, peer):
        self.peer = peer

    def disconnect(self):
        self.send_queue.stop()
        self.send_queue = None

    def start_otr(self, secret=None):
        self.secret = secret
        self.otr_session.start()

    def stop_otr(self):
        self.otr_session.stop()

    def inject_otr_message(self, message):
        log.debug("{0.name} sending: {1!r}".format(self, message))
        self.send_queue.put(message)

    def send(self, content, content_type='text/plain'):
        log.debug("{0.name} encoding: {1!r}".format(self, content))
        self.sent_message = content
        content = self.otr_session.handle_output(content, content_type)
        log.debug("{0.name} sending: {1!r}".format(self, content))
        self.send_queue.put(content)

    def receive(self, message):
        # log.debug("{0.name} received: {1!r}".format(self, message))
        try:
            message = self.otr_session.handle_input(message, 'text/plain')
        except IgnoreMessage:
            return
        else:
            log.debug("{0.name} decoded:  {1!r}".format(self, message))
            self.received_message = message
            self.all_done.set()

    def handle_notification(self, notification):
        handler = getattr(self, '_NH_{0.name}'.format(notification), Null)
        handler(notification)

    def _NH_OTRSessionStateChanged(self, notification):
        if notification.data.new_state is OTRState.Encrypted:
            self.ake_done.set()
            if self.secret is None:
                self.smp_done.set()
            elif self.name < self.peer.name:
                self.otr_session.smp_verify(secret=self.secret)
        elif notification.data.old_state is OTRState.Encrypted:
            self.otr_done.set()

    def _NH_OTRSessionSMPVerificationDidStart(self, notification):
        if notification.data.originator == 'remote':
            if self.secret:
                self.otr_session.smp_answer(secret=self.secret)
            else:
                self.otr_session.smp_abort()

    def _NH_OTRSessionSMPVerificationDidNotStart(self, notification):
        self.smp_status = notification.data.reason
        self.smp_done.set()

    def _NH_OTRSessionSMPVerificationDidEnd(self, notification):
        self.same_secrets = notification.data.same_secrets
        self.smp_status = notification.data.status
        self.smp_done.set()
Example #4
0
class OTREncryption(object):
    implements(IObserver)

    def __init__(self, stream):
        self.stream = stream
        self.otr_cache = OTRCache()
        self.otr_session = OTRSession(self.otr_cache.private_key, self.stream, supported_versions={3})  # we need at least OTR-v3 for question based SMP

        notification_center = NotificationCenter()
        notification_center.add_observer(self, sender=stream)
        notification_center.add_observer(self, sender=self.otr_session)

    @property
    def active(self):
        try:
            return self.otr_session.encrypted
        except AttributeError:
            return False

    @property
    def cipher(self):
        return 'AES-128-CTR' if self.active else None

    @property
    def key_fingerprint(self):
        try:
            return self.otr_session.local_private_key.public_key.fingerprint
        except AttributeError:
            return None

    @property
    def peer_fingerprint(self):
        try:
            return self.otr_session.remote_public_key.fingerprint
        except AttributeError:
            return None

    @property
    def peer_name(self):
        try:
            return self.__dict__['peer_name']
        except KeyError:
            trusted_peer = self.otr_cache.trusted_peers.get(self.peer_fingerprint, None)
            if trusted_peer is None:
                return u''
            else:
                return self.__dict__.setdefault('peer_name', trusted_peer.description)

    @peer_name.setter
    def peer_name(self, name):
        old_name = self.peer_name
        new_name = self.__dict__['peer_name'] = name
        if old_name != new_name:
            trusted_peer = self.otr_cache.trusted_peers.get(self.peer_fingerprint, None)
            if trusted_peer is not None:
                trusted_peer.description = new_name
                self.otr_cache.save()
            notification_center = NotificationCenter()
            notification_center.post_notification("ChatStreamOTRPeerNameChanged", sender=self.stream, data=NotificationData(name=name))

    @property
    def verified(self):
        return self.peer_fingerprint in self.otr_cache.trusted_peers

    @verified.setter
    def verified(self, value):
        peer_fingerprint = self.peer_fingerprint
        old_verified = peer_fingerprint in self.otr_cache.trusted_peers
        new_verified = bool(value)
        if peer_fingerprint is None or new_verified == old_verified:
            return
        if new_verified:
            self.otr_cache.trusted_peers.add(OTRTrustedPeer(peer_fingerprint, description=self.peer_name))
        else:
            self.otr_cache.trusted_peers.remove(peer_fingerprint)
        self.otr_cache.save()
        notification_center = NotificationCenter()
        notification_center.post_notification("ChatStreamOTRVerifiedStateChanged", sender=self.stream, data=NotificationData(verified=new_verified))

    @run_in_twisted_thread
    def start(self):
        if self.otr_session is not None:
            self.otr_session.start()

    @run_in_twisted_thread
    def stop(self):
        if self.otr_session is not None:
            self.otr_session.stop()

    @run_in_twisted_thread
    def smp_verify(self, secret, question=None):
        self.otr_session.smp_verify(secret, question)

    @run_in_twisted_thread
    def smp_answer(self, secret):
        self.otr_session.smp_answer(secret)

    @run_in_twisted_thread
    def smp_abort(self):
        self.otr_session.smp_abort()

    def handle_notification(self, notification):
        handler = getattr(self, '_NH_%s' % notification.name, Null)
        handler(notification)

    def _NH_MediaStreamDidStart(self, notification):
        if self.stream.start_otr:
            self.otr_session.start()

    def _NH_MediaStreamDidEnd(self, notification):
        notification.center.remove_observer(self, sender=self.stream)
        notification.center.remove_observer(self, sender=self.otr_session)
        self.otr_session.stop()
        self.otr_session = None
        self.stream = None

    _NH_MediaStreamDidNotInitialize = _NH_MediaStreamDidEnd

    def _NH_OTRSessionStateChanged(self, notification):
        notification.center.post_notification('ChatStreamOTREncryptionStateChanged', sender=self.stream, data=notification.data)

    def _NH_OTRSessionSMPVerificationDidStart(self, notification):
        notification.center.post_notification('ChatStreamSMPVerificationDidStart', sender=self.stream, data=notification.data)

    def _NH_OTRSessionSMPVerificationDidNotStart(self, notification):
        notification.center.post_notification('ChatStreamSMPVerificationDidNotStart', sender=self.stream, data=notification.data)

    def _NH_OTRSessionSMPVerificationDidEnd(self, notification):
        notification.center.post_notification('ChatStreamSMPVerificationDidEnd', sender=self.stream, data=notification.data)