Beispiel #1
0
    def archiving_accepted(self, form):
        negotiated = {}
        ask_user = {}
        not_acceptable = []

        if form['logging'] not in self.archiving_logging_preference():
            raise

        self.negotiated['logging'] = form['logging']

        accept = nbxmpp.Message()
        feature = accept.NT.feature
        feature.setNamespace(nbxmpp.NS_FEATURE)

        result = nbxmpp.DataForm(typ='result')

        result.addChild(node=nbxmpp.DataField(name='FORM_TYPE',
                value='urn:xmpp:ssn'))
        result.addChild(node=nbxmpp.DataField(name='accept', value='1'))

        feature.addChild(node=result)

        self.send(accept)
        if self.negotiated['logging'] == 'mustnot':
            self.loggable = False
        log.debug('archiving session accepted: %s' % self.loggable)
        self.status = 'active'
        self.archiving = True
        if self.control:
            self.control.print_archiving_session_details()
Beispiel #2
0
    def read_invitation(self, msg):
        invite = msg.getTag('invite', namespace=NS_GAMES)
        game = invite.getTag('game')
        x = game.getTag('x', namespace='jabber:x:data')

        form = nbxmpp.DataForm(node=str(x))

        if form.getField('role'):
            self.role_o = form.getField('role').getValues()[0]
        else:
            self.role_o = 'x'

        if form.getField('rows'):
            self.rows = int(form.getField('rows').getValues()[0])
        else:
            self.rows = 3

        if form.getField('cols'):
            self.cols = int(form.getField('cols').getValues()[0])
        else:
            self.cols = 3

        # number in a row needed to win
        if form.getField('strike'):
            self.strike = int(form.getField('strike').getValues()[0])
        else:
            self.strike = 3
Beispiel #3
0
    def negotiate_archiving(self):
        self.negotiated = {}

        request = nbxmpp.Message()
        feature = request.NT.feature
        feature.setNamespace(nbxmpp.NS_FEATURE)

        x = nbxmpp.DataForm(typ='form')

        x.addChild(node=nbxmpp.DataField(name='FORM_TYPE', value='urn:xmpp:ssn',
            typ='hidden'))
        x.addChild(node=nbxmpp.DataField(name='accept', value='1',
            typ='boolean', required=True))

        x.addChild(node=nbxmpp.DataField(name='logging', typ='list-single',
            options=self.archiving_logging_preference(), required=True))

        x.addChild(node=nbxmpp.DataField(name='disclosure', typ='list-single',
            options=['never'], required=True))
        x.addChild(node=nbxmpp.DataField(name='security', typ='list-single',
            options=['none'], required=True))

        feature.addChild(node=x)

        self.status = 'requested-archiving'

        self.send(request)
Beispiel #4
0
    def get_archive_query(self, query_id, jid=None, start=None, end=None, with_=None,
                          after=None, max_=30):
        # Muc archive query?
        namespace = muc_caps_cache.get_mam_namespace(jid)
        if namespace is None:
            # Query to our own archive
            namespace = self.archiving_namespace

        iq = nbxmpp.Iq('set', to=jid)
        query = iq.addChild('query', namespace=namespace)
        form = query.addChild(node=nbxmpp.DataForm(typ='submit'))
        field = nbxmpp.DataField(typ='hidden',
                                 name='FORM_TYPE',
                                 value=namespace)
        form.addChild(node=field)
        if start:
            field = nbxmpp.DataField(typ='text-single',
                                     name='start',
                                     value=start.strftime('%Y-%m-%dT%H:%M:%SZ'))
            form.addChild(node=field)
        if end:
            field = nbxmpp.DataField(typ='text-single',
                                     name='end',
                                     value=end.strftime('%Y-%m-%dT%H:%M:%SZ'))
            form.addChild(node=field)
        if with_:
            field = nbxmpp.DataField(typ='jid-single', name='with', value=with_)
            form.addChild(node=field)

        set_ = query.setTag('set', namespace=nbxmpp.NS_RSM)
        set_.setTagData('max', max_)
        if after:
            set_.setTagData('after', after)
        query.setAttr('queryid', query_id)
        return iq
Beispiel #5
0
 def _siResultCB(self, con, iq_obj):
     file_props = FilesProp.getFileProp(self.name, iq_obj.getAttr('id'))
     if not file_props:
         return
     if file_props.request_id:
         # we have already sent streamhosts info
         return
     file_props.receiver = self._ft_get_from(iq_obj)
     si = iq_obj.getTag('si')
     file_tag = si.getTag('file')
     range_tag = None
     if file_tag:
         range_tag = file_tag.getTag('range')
     if range_tag:
         offset = range_tag.getAttr('offset')
         if offset:
             file_props.offset = int(offset)
         length = range_tag.getAttr('length')
         if length:
             file_props.length = int(length)
     feature = si.setTag('feature')
     if feature.getNamespace() != nbxmpp.NS_FEATURE:
         return
     form_tag = feature.getTag('x')
     form = nbxmpp.DataForm(node=form_tag)
     field = form.getField('stream-method')
     if field.getValue() == nbxmpp.NS_BYTESTREAM:
         self._send_socks5_info(file_props)
         raise nbxmpp.NodeProcessed
     if field.getValue() == nbxmpp.NS_IBB:
         sid = file_props.sid
         file_props.transport_sid = sid
         fp = open(file_props.file_name, 'r')
         self.OpenStream(sid, file_props.receiver, fp)
         raise nbxmpp.NodeProcessed
Beispiel #6
0
 def request_archive(self,
                     start=None,
                     end=None,
                     with_=None,
                     after=None,
                     max=30):
     iq_ = nbxmpp.Iq('set')
     query = iq_.addChild('query', namespace=nbxmpp.NS_MAM)
     x = query.addChild(node=nbxmpp.DataForm(typ='submit'))
     x.addChild(node=nbxmpp.DataField(
         typ='hidden', name='FORM_TYPE', value=nbxmpp.NS_MAM))
     if start:
         x.addChild(node=nbxmpp.DataField(
             typ='text-single', name='start', value=start))
     if end:
         x.addChild(node=nbxmpp.DataField(
             typ='text-single', name='end', value=end))
     if with_:
         x.addChild(node=nbxmpp.DataField(
             typ='jid-single', name='with', value=with_))
     set_ = query.setTag('set', namespace=nbxmpp.NS_RSM)
     set_.setTagData('max', max)
     if after:
         set_.setTagData('after', after)
     queryid_ = self.connection.getAnID()
     query.setAttr('queryid', queryid_)
     id_ = self.connection.getAnID()
     iq_.setID(id_)
     self.awaiting_answers[queryid_] = (MAM_RESULTS_ARRIVED, )
     self.connection.send(iq_)
Beispiel #7
0
    def append(self, stanza):
        jid = stanza.getFrom()
        identities, features, data = [], [], []
        query_childs = stanza.getQueryChildren()
        if not query_childs:
            from gajim.common import app
            app.log('gajim.muc').warning('%s returned empty disco info', jid)
            return

        for child in query_childs:
            if child.getName() == 'identity':
                attr = {}
                for key in child.getAttrs().keys():
                    attr[key] = child.getAttr(key)
                identities.append(attr)
            elif child.getName() == 'feature':
                features.append(child.getAttr('var'))
            elif child.getName() == 'x':
                if child.getNamespace() == nbxmpp.NS_DATA:
                    data.append(nbxmpp.DataForm(node=child))

        if nbxmpp.NS_MUC not in features:
            # Not a MUC, dont cache info
            return

        self.cache[jid] = self.DiscoInfo(identities, features, data)
Beispiel #8
0
    def parse_info_response(cls, stanza):
        identities, features, data, node = [], [], [], None
        q = stanza.getTag('query')
        node = q.getAttr('node')
        if not node:
            node = ''

        qc = stanza.getQueryChildren()
        if not qc:
            qc = []

        for i in qc:
            if i.getName() == 'identity':
                attr = {}
                for key in i.getAttrs().keys():
                    attr[key] = i.getAttr(key)
                identities.append(attr)
            elif i.getName() == 'feature':
                var = i.getAttr('var')
                if var:
                    features.append(var)
            elif i.getName() == 'x' and i.getNamespace() == nbxmpp.NS_DATA:
                data.append(nbxmpp.DataForm(node=i))

        return identities, features, data, node
Beispiel #9
0
 def send_file_request(self, file_props):
     """
     Send iq for new FT request
     """
     if not self.connection or self.connected < 2:
         return
     file_props.sender = self._ft_get_our_jid()
     fjid = self._ft_get_receiver_jid(file_props)
     iq = nbxmpp.Iq(to=fjid, typ='set')
     iq.setID(file_props.sid)
     si = iq.setTag('si', namespace=nbxmpp.NS_SI)
     si.setAttr('profile', nbxmpp.NS_FILE)
     si.setAttr('id', file_props.sid)
     file_tag = si.setTag('file', namespace=nbxmpp.NS_FILE)
     file_tag.setAttr('name', file_props.name)
     file_tag.setAttr('size', file_props.size)
     desc = file_tag.setTag('desc')
     if file_props.desc:
         desc.setData(file_props.desc)
     file_tag.setTag('range')
     feature = si.setTag('feature', namespace=nbxmpp.NS_FEATURE)
     _feature = nbxmpp.DataForm(typ='form')
     feature.addChild(node=_feature)
     field = _feature.setField('stream-method')
     field.setAttr('type', 'list-single')
     field.addOption(nbxmpp.NS_BYTESTREAM)
     field.addOption(nbxmpp.NS_IBB)
     self.connection.send(iq)
Beispiel #10
0
    def send_invitation(self):
        msg = nbxmpp.Message()

        invite = msg.NT.invite
        invite.setNamespace(NS_GAMES)
        invite.setAttr('type', 'new')

        game = invite.NT.game
        game.setAttr('var', NS_GAMES_TICTACTOE)

        x = nbxmpp.DataForm(typ='submit')
        f = x.setField('role')
        f.setType('list-single')
        f.setValue('x')
        f = x.setField('rows')
        f.setType('text-single')
        f.setValue(str(self.base.plugin.config['board_size']))
        f = x.setField('cols')
        f.setType('text-single')
        f.setValue(str(self.base.plugin.config['board_size']))
        f = x.setField('strike')
        f.setType('text-single')
        f.setValue(str(self.base.plugin.config['board_size']))

        game.addChild(node=x)

        self.send(msg)
Beispiel #11
0
    def send_file_approval(self, file_props):
        """
        Send iq, confirming that we want to download the file
        """
        # user response to ConfirmationDialog may come after we've disconneted
        if not self.connection or self.connected < 2:
            return

        # file transfer initiated by a jingle session
        log.info("send_file_approval: jingle session accept")
        if file_props.session_type == 'jingle':
            session = self.get_jingle_session(file_props.sender,
                                              file_props.sid)
            if not session:
                return
            content = None
            for c in session.contents.values():
                if c.transport.sid == file_props.transport_sid:
                    content = c
                    break
            if not content:
                return
            if not session.accepted:
                content = session.get_content('file', content.name)
                if content.use_security:
                    fingerprint = content.x509_fingerprint
                    if not jingle_xtls.check_cert(
                            gajim.get_jid_without_resource(file_props.sender),
                            fingerprint):
                        id_ = jingle_xtls.send_cert_request(
                            self, file_props.sender)
                        jingle_xtls.key_exchange_pend(id_,
                                                      content.on_cert_received,
                                                      [])
                        return
                session.approve_session()

            session.approve_content('file', content.name)
            return

        iq = nbxmpp.Iq(to=file_props.sender, typ='result')
        iq.setAttr('id', file_props.request_id)
        si = iq.setTag('si', namespace=nbxmpp.NS_SI)
        if file_props.offset:
            file_tag = si.setTag('file', namespace=nbxmpp.NS_FILE)
            range_tag = file_tag.setTag('range')
            range_tag.setAttr('offset', file_props.offset)
        feature = si.setTag('feature', namespace=nbxmpp.NS_FEATURE)
        _feature = nbxmpp.DataForm(typ='submit')
        feature.addChild(node=_feature)
        field = _feature.setField('stream-method')
        field.delAttr('type')
        if nbxmpp.NS_BYTESTREAM in file_props.stream_methods:
            field.setValue(nbxmpp.NS_BYTESTREAM)
        else:
            file_props.transport_sid = file_props.sid
            field.setValue(nbxmpp.NS_IBB)
        self.connection.send(iq)
Beispiel #12
0
 def request_voice(self, room):
     if not app.account_is_connected(self._account):
         return
     message = nbxmpp.Message(to=room)
     x = nbxmpp.DataForm(typ='submit')
     x.addChild(node=nbxmpp.DataField(name='FORM_TYPE',
                                      value=nbxmpp.NS_MUC + '#request'))
     x.addChild(node=nbxmpp.DataField(
         name='muc#role', value='participant', typ='text-single'))
     message.addChild(node=x)
     self._con.connection.send(message)
Beispiel #13
0
    def on_cancel_button_clicked(self, widget):
        rejection = nbxmpp.Message(self.jid)
        rejection.setThread(self.session.thread_id)
        feature = rejection.NT.feature
        feature.setNamespace(nbxmpp.NS_FEATURE)

        x = nbxmpp.DataForm(typ='submit')
        x.addChild(node=nbxmpp.DataField('FORM_TYPE', value='urn:xmpp:ssn'))
        x.addChild(
            node=nbxmpp.DataField('accept', value='false', typ='boolean'))

        feature.addChild(node=x)

        app.connections[self.account].send_stanza(rejection)

        self.window.destroy()
Beispiel #14
0
    def reject_negotiation(self, body=None):
        msg = nbxmpp.Message()
        feature = msg.NT.feature
        feature.setNamespace(nbxmpp.NS_FEATURE)

        x = nbxmpp.DataForm(typ='submit')
        x.addChild(node=nbxmpp.DataField(name='FORM_TYPE',
            value='urn:xmpp:ssn'))
        x.addChild(node=nbxmpp.DataField(name='accept', value='0'))

        feature.addChild(node=x)

        if body:
            msg.setBody(body)

        self.send(msg)

        self.cancelled_negotiation()
Beispiel #15
0
    def terminate(self, send_termination = True):
        # only send termination message if we've sent a message and think they
        # have XEP-0201 support
        if send_termination and self.last_send > 0 and \
        (self.received_thread_id or self.last_receive == 0):
            msg = nbxmpp.Message()
            feature = msg.NT.feature
            feature.setNamespace(nbxmpp.NS_FEATURE)

            x = nbxmpp.DataForm(typ='submit')
            x.addChild(node=nbxmpp.DataField(name='FORM_TYPE',
                value='urn:xmpp:ssn'))
            x.addChild(node=nbxmpp.DataField(name='terminate', value='1'))

            feature.addChild(node=x)

            self.send(msg)

        self.status = None
Beispiel #16
0
    def respond_archiving(self, form):
        field = form.getField('logging')
        options = [x[1] for x in field.getOptions()]
        values = field.getValues()

        logging = self.archiving_logging_preference(options)
        self.negotiated['logging'] = logging

        response = nbxmpp.Message()
        feature = response.NT.feature
        feature.setNamespace(nbxmpp.NS_FEATURE)

        x = nbxmpp.DataForm(typ='submit')

        x.addChild(node=nbxmpp.DataField(name='FORM_TYPE',
            value='urn:xmpp:ssn'))
        x.addChild(node=nbxmpp.DataField(name='accept', value='true'))

        x.addChild(node=nbxmpp.DataField(name='logging', value=logging))

        self.status = 'responded-archiving'

        feature.addChild(node=x)

        if not logging:
            response = nbxmpp.Error(response, nbxmpp.ERR_NOT_ACCEPTABLE)

            feature = nbxmpp.Node(nbxmpp.NS_FEATURE + ' feature')

            n = nbxmpp.Node('field')
            n['var'] = 'logging'
            feature.addChild(node=n)

            response.T.error.addChild(node=feature)

        self.send(response)
Beispiel #17
0
    def negotiate_e2e(self, sigmai):
        self.negotiated = {}

        request = nbxmpp.Message()
        feature = request.NT.feature
        feature.setNamespace(nbxmpp.NS_FEATURE)

        x = nbxmpp.DataForm(typ='form')

        x.addChild(node=nbxmpp.DataField(name='FORM_TYPE', value='urn:xmpp:ssn',
            typ='hidden'))
        x.addChild(node=nbxmpp.DataField(name='accept', value='1',
            typ='boolean', required=True))

        # this field is incorrectly called 'otr' in XEPs 0116 and 0217
        x.addChild(node=nbxmpp.DataField(name='logging', typ='list-single',
            options=self.logging_preference(), required=True))

        # unsupported options: 'disabled', 'enabled'
        x.addChild(node=nbxmpp.DataField(name='disclosure', typ='list-single',
            options=['never'], required=True))
        x.addChild(node=nbxmpp.DataField(name='security', typ='list-single',
            options=['e2e'], required=True))
        x.addChild(node=nbxmpp.DataField(name='crypt_algs', value='aes128-ctr',
            typ='hidden'))
        x.addChild(node=nbxmpp.DataField(name='hash_algs', value='sha256',
            typ='hidden'))
        x.addChild(node=nbxmpp.DataField(name='compress', value='none',
            typ='hidden'))

        # unsupported options: 'iq', 'presence'
        x.addChild(node=nbxmpp.DataField(name='stanzas', typ='list-multi',
            options=['message']))

        x.addChild(node=nbxmpp.DataField(name='init_pubkey', options=['none',
            'key', 'hash'], typ='list-single'))

        # FIXME store key, use hash
        x.addChild(node=nbxmpp.DataField(name='resp_pubkey', options=['none',
            'key'], typ='list-single'))

        x.addChild(node=nbxmpp.DataField(name='ver', value='1.0', typ='hidden'))

        x.addChild(node=nbxmpp.DataField(name='rekey_freq', value='4294967295',
            typ='hidden'))

        x.addChild(node=nbxmpp.DataField(name='sas_algs', value='sas28x5',
            typ='hidden'))
        x.addChild(node=nbxmpp.DataField(name='sign_algs',
            value='http://www.w3.org/2000/09/xmldsig#rsa-sha256', typ='hidden'))

        self.n_s = crypto.generate_nonce()

        x.addChild(node=nbxmpp.DataField(name='my_nonce',
            value=base64.b64encode(self.n_s).decode('utf-8'), typ='hidden'))

        modp_options = [ int(g) for g in gajim.config.get('esession_modp').split(
            ',') ]

        x.addChild(node=nbxmpp.DataField(name='modp', typ='list-single',
            options=[[None, y] for y in modp_options]))

        x.addChild(node=self.make_dhfield(modp_options, sigmai))
        self.sigmai = sigmai

        self.form_s = ''.join(nbxmpp.c14n.c14n(el, self._is_buggy_gajim()) for \
            el in x.getChildren())

        feature.addChild(node=x)

        self.status = 'requested-e2e'

        self.send(request)
Beispiel #18
0
    def respond_e2e_bob(self, form, negotiated, not_acceptable):
        """
        4.3 esession response (bob)
        """
        response = nbxmpp.Message()
        feature = response.NT.feature
        feature.setNamespace(nbxmpp.NS_FEATURE)

        x = nbxmpp.DataForm(typ='submit')

        x.addChild(node=nbxmpp.DataField(name='FORM_TYPE',
            value='urn:xmpp:ssn'))
        x.addChild(node=nbxmpp.DataField(name='accept', value='true'))

        for name in negotiated:
            # some fields are internal and should not be sent
            if not name in ('send_pubkey', 'recv_pubkey'):
                x.addChild(node=nbxmpp.DataField(name=name,
                    value=negotiated[name]))

        self.negotiated = negotiated

        # the offset of the group we chose (need it to match up with the dhhash)
        group_order = 0
        modp_f = form.getField('modp')
        if not modp_f:
            return
        self.modp = int(modp_f.getOptions()[group_order][1])
        x.addChild(node=nbxmpp.DataField(name='modp', value=self.modp))

        g = dh.generators[self.modp]
        p = dh.primes[self.modp]

        self.n_o = base64.b64decode(form['my_nonce'])

        dhhashes_f = form.getField('dhhashes')
        if not dhhashes_f:
            return
        dhhashes = dhhashes_f.getValues()
        self.negotiated['He'] = base64.b64decode(dhhashes[group_order].encode(
            'utf8'))

        bytes = int(self.n / 8)

        self.n_s = crypto.generate_nonce()

        # n-bit random number
        self.c_o = crypto.decode_mpi(crypto.random_bytes(bytes))
        self.c_s = self.c_o ^ (2 ** (self.n - 1))

        self.y = crypto.srand(2 ** (2 * self.n - 1), p - 1)
        self.d = crypto.powmod(g, self.y, p)

        to_add = {'my_nonce': self.n_s,
                'dhkeys': crypto.encode_mpi(self.d),
                'counter': crypto.encode_mpi(self.c_o),
                'nonce': self.n_o}

        for name in to_add:
            b64ed = base64.b64encode(to_add[name]).decode('utf-8')
            x.addChild(node=nbxmpp.DataField(name=name, value=b64ed))

        self.form_o = ''.join(nbxmpp.c14n.c14n(el, self._is_buggy_gajim()) for \
            el in form.getChildren())
        self.form_s = ''.join(nbxmpp.c14n.c14n(el, self._is_buggy_gajim()) for \
            el in x.getChildren())

        self.status = 'responded-e2e'

        feature.addChild(node=x)

        if not_acceptable:
            response = nbxmpp.Error(response, nbxmpp.ERR_NOT_ACCEPTABLE)

            feature = nbxmpp.Node(nbxmpp.NS_FEATURE + ' feature')

            for f in not_acceptable:
                n = nbxmpp.Node('field')
                n['var'] = f
                feature.addChild(node=n)

            response.T.error.addChild(node=feature)

        self.send(response)
Beispiel #19
0
    def accept_e2e_bob(self, form):
        """
        4.5 esession accept (bob)
        """
        response = nbxmpp.Message()

        init = response.NT.init
        init.setNamespace(nbxmpp.NS_ESESSION_INIT)

        x = nbxmpp.DataForm(typ='result')

        for field in ('nonce', 'dhkeys', 'rshashes', 'identity', 'mac'):
            # FIXME: will do nothing in real world...
            assert field in form.asDict(), "alice's form didn't have a %s field" \
                    % field

        # 4.5.1 generating provisory session keys
        e = crypto.decode_mpi(base64.b64decode(form['dhkeys']))
        p = dh.primes[self.modp]

        if crypto.sha256(crypto.encode_mpi(e)) != self.negotiated['He']:
            raise NegotiationError('SHA256(e) != He')

        k = self.get_shared_secret(e, self.y, p)
        self.kc_o, self.km_o, self.ks_o = self.generate_initiator_keys(k)

        # 4.5.2 verifying alice's identity
        self.verify_identity(form, e, False, 'a')

        # 4.5.4 generating bob's final session keys
        srs = b''

        srses = secrets.secrets().retained_secrets(self.conn.name,
                self.jid.getStripped())
        rshashes = [base64.b64decode(rshash) for rshash in form.getField(
                'rshashes').getValues()]

        for s in srses:
            secret = s[0]
            if self.hmac(self.n_o, secret) in rshashes:
                srs = secret
                break

        # other shared secret
        # (we're not using one)
        oss = b''

        k = crypto.sha256(k + srs + oss)

        self.kc_s, self.km_s, self.ks_s = self.generate_responder_keys(k)
        self.kc_o, self.km_o, self.ks_o = self.generate_initiator_keys(k)

        # 4.5.5
        if srs:
            srshash = self.hmac(srs, b'Shared Retained Secret')
        else:
            srshash = crypto.random_bytes(32)

        x.addChild(node=nbxmpp.DataField(name='FORM_TYPE',
            value='urn:xmpp:ssn'))
        x.addChild(node=nbxmpp.DataField(name='nonce', value=base64.b64encode(
            self.n_o).decode('utf-8')))
        x.addChild(node=nbxmpp.DataField(name='srshash', value=base64.b64encode(
            srshash).decode('utf-8')))

        for datafield in self.make_identity(x, self.d):
            x.addChild(node=datafield)

        init.addChild(node=x)

        self.send(response)

        self.do_retained_secret(k, srs)

        if self.negotiated['logging'] == 'mustnot':
            self.loggable = False

        self.status = 'active'
        self.enable_encryption = True

        if self.control:
            self.control.print_esession_details()

        self.stop_archiving_for_session()
Beispiel #20
0
    def accept_e2e_alice(self, form, negotiated):
        """
        'Alice Accepts', continued
        """
        self.encryptable_stanzas = ['message']
        self.sas_algs = 'sas28x5'
        self.cipher = AES
        self.hash_alg = sha256
        self.compression = None

        self.negotiated = negotiated

        accept = nbxmpp.Message()
        feature = accept.NT.feature
        feature.setNamespace(nbxmpp.NS_FEATURE)

        result = nbxmpp.DataForm(typ='result')

        self.c_s = crypto.decode_mpi(base64.b64decode(form['counter']))
        self.c_o = self.c_s ^ (2 ** (self.n - 1))
        self.n_o = base64.b64decode(form['my_nonce'])

        mod_p = int(form['modp'])
        p = dh.primes[mod_p]
        x = self.xes[mod_p]
        e = self.es[mod_p]

        self.d = crypto.decode_mpi(base64.b64decode(form['dhkeys']))
        self.k = self.get_shared_secret(self.d, x, p)

        result.addChild(node=nbxmpp.DataField(name='FORM_TYPE',
                value='urn:xmpp:ssn'))
        result.addChild(node=nbxmpp.DataField(name='accept', value='1'))
        result.addChild(node=nbxmpp.DataField(name='nonce',
                value=base64.b64encode(self.n_o).decode('utf-8')))

        self.kc_s, self.km_s, self.ks_s = self.generate_initiator_keys(self.k)

        if self.sigmai:
            self.kc_o, self.km_o, self.ks_o = self.generate_responder_keys(self.k)
            self.verify_identity(form, self.d, True, 'b')
        else:
            srses = secrets.secrets().retained_secrets(self.conn.name,
                    self.jid.getStripped())
            rshashes = [self.hmac(self.n_s, rs[0]) for rs in srses]

            if not rshashes:
                # we've never spoken before, but we'll pretend we have
                rshash_size = self.hash_alg().digest_size
                rshashes.append(crypto.random_bytes(rshash_size))

            rshashes = [base64.b64encode(rshash).decode('utf-8') for rshash in \
                rshashes]
            result.addChild(node=nbxmpp.DataField(name='rshashes',
                value=rshashes))
            result.addChild(node=nbxmpp.DataField(name='dhkeys',
                value=base64.b64encode(crypto.encode_mpi(e)).decode('utf-8')))

            self.form_o = ''.join(nbxmpp.c14n.c14n(el, self._is_buggy_gajim()) \
                for el in form.getChildren())

        # MUST securely destroy K unless it will be used later to generate the
        # final shared secret

        for datafield in self.make_identity(result, e):
            result.addChild(node=datafield)

        feature.addChild(node=result)
        self.send(accept)

        if self.sigmai:
            self.status = 'active'
            self.enable_encryption = True
        else:
            self.status = 'identified-alice'