Example #1
0
    def accept_e2e_bob(self, form):
        response = xmpp.Message()

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

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

        for field in ('nonce', 'dhkeys', 'rshashes', 'identity', 'mac'):
            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 exceptions.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 = ''

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

        for (secret, verified) in srses:
            if self.hmac(self.n_o, secret) in rshashes:
                srs = secret
                break

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

        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, 'Shared Retained Secret')
        else:
            srshash = crypto.random_bytes(32)

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

        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()
Example #2
0
    def respond_e2e_bob(self, form, negotiated, not_acceptable):
        response = xmpp.Message()
        feature = response.NT.feature
        feature.setNamespace(xmpp.NS_FEATURE)

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

        x.addChild(node=xmpp.DataField(name='FORM_TYPE', value='urn:xmpp:ssn'))
        x.addChild(node=xmpp.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=xmpp.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
        self.modp = int(form.getField('modp').getOptions()[group_order][1])
        x.addChild(node=xmpp.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 = form.getField('dhhashes').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])
            x.addChild(node=xmpp.DataField(name=name, value=b64ed))

        self.form_o = ''.join(
            map(lambda el: xmpp.c14n.c14n(el), form.getChildren()))
        self.form_s = ''.join(
            map(lambda el: xmpp.c14n.c14n(el), x.getChildren()))

        self.status = 'responded-e2e'

        feature.addChild(node=x)

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

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

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

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

        self.send(response)
Example #3
0
    def accept_e2e_alice(self, form, negotiated):
        self.encryptable_stanzas = ['message']
        self.sas_algs = 'sas28x5'
        self.cipher = AES
        self.hash_alg = SHA256
        self.compression = None

        self.negotiated = negotiated

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

        result = xmpp.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=xmpp.DataField(name='FORM_TYPE', value='urn:xmpp:ssn'))
        result.addChild(node=xmpp.DataField(name='accept', value='1'))
        result.addChild(node=xmpp.DataField(name='nonce',
                                            value=base64.b64encode(self.n_o)))

        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) for (rs, v) 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) for rshash in rshashes]
            result.addChild(
                node=xmpp.DataField(name='rshashes', value=rshashes))
            result.addChild(node=xmpp.DataField(
                name='dhkeys', value=base64.b64encode(crypto.encode_mpi(e))))

            self.form_o = ''.join(
                map(lambda el: xmpp.c14n.c14n(el), 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'
Example #4
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 = ''

        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 = ''

        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, '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)))
        x.addChild(node=nbxmpp.DataField(name='srshash', value=base64.b64encode(
            srshash)))

        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()
Example #5
0
    def verify_identity(self, form, dh_i, sigmai, i_o):
        m_o = base64.b64decode(form['mac'])
        id_o = base64.b64decode(form['identity'])

        m_o_calculated = self.hmac(self.km_o,
                                   crypto.encode_mpi(self.c_o) + id_o)

        if m_o_calculated != m_o:
            raise exceptions.NegotiationError, 'calculated m_%s differs from received m_%s' % (
                i_o, i_o)

        if i_o == 'a' and self.sas_algs == 'sas28x5':
            # we don't need to calculate this if there's a verified retained secret
            # (but we do anyways)
            self.sas = crypto.sas_28x5(m_o, self.form_s)

        if self.negotiated['recv_pubkey']:
            plaintext = self.decrypt(id_o)
            parsed = xmpp.Node(node='<node>' + plaintext + '</node>')

            if self.negotiated['recv_pubkey'] == 'hash':
                fingerprint = parsed.getTagData('fingerprint')

                # XXX find stored pubkey or terminate session
                raise 'unimplemented'
            else:
                if self.negotiated['sign_algs'] == (XmlDsig + 'rsa-sha256'):
                    keyvalue = parsed.getTag(name='RSAKeyValue',
                                             namespace=XmlDsig)

                    n, e = map(
                        lambda x: crypto.decode_mpi(
                            base64.b64decode(keyvalue.getTagData(x))),
                        ('Modulus', 'Exponent'))
                    eir_pubkey = RSA.construct((n, long(e)))

                    pubkey_o = xmpp.c14n.c14n(keyvalue)
                else:
                    # XXX DSA, etc.
                    raise 'unimplemented'

            enc_sig = parsed.getTag(name='SignatureValue',
                                    namespace=XmlDsig).getData()
            signature = (crypto.decode_mpi(base64.b64decode(enc_sig)), )
        else:
            mac_o = self.decrypt(id_o)
            pubkey_o = ''

        c7l_form = self.c7lize_mac_id(form)

        content = self.n_s + self.n_o + crypto.encode_mpi(dh_i) + pubkey_o

        if sigmai:
            self.form_o = c7l_form
            content += self.form_o
        else:
            form_o2 = c7l_form
            content += self.form_o + form_o2

        mac_o_calculated = self.hmac(self.ks_o, content)

        if self.negotiated['recv_pubkey']:
            hash = crypto.sha256(mac_o_calculated)

            if not eir_pubkey.verify(hash, signature):
                raise exceptions.NegotiationError, 'public key signature verification failed!'

        elif mac_o_calculated != mac_o:
            raise exceptions.NegotiationError, 'calculated mac_%s differs from received mac_%s' % (
                i_o, i_o)
Example #6
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])
            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)
Example #7
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)))

        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) 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))))

            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'
Example #8
0
    def verify_identity(self, form, dh_i, sigmai, i_o):
        m_o = base64.b64decode(form['mac'])
        id_o = base64.b64decode(form['identity'])

        m_o_calculated = self.hmac(self.km_o, crypto.encode_mpi(self.c_o) + id_o)

        if m_o_calculated != m_o:
            raise NegotiationError('calculated m_%s differs from received m_%s' %
                    (i_o, i_o))

        if i_o == 'a' and self.sas_algs == 'sas28x5':
            # we don't need to calculate this if there's a verified retained secret
            # (but we do anyways)
            self.sas = crypto.sas_28x5(m_o, self.form_s)

        if self.negotiated['recv_pubkey']:
            plaintext = self.decrypt(id_o)
            parsed = nbxmpp.Node(node='<node>' + plaintext + '</node>')

            if self.negotiated['recv_pubkey'] == 'hash':
                # fingerprint = parsed.getTagData('fingerprint')
                # FIXME find stored pubkey or terminate session
                raise NotImplementedError()
            else:
                if self.negotiated['sign_algs'] == (XmlDsig + 'rsa-sha256'):
                    keyvalue = parsed.getTag(name='RSAKeyValue', namespace=XmlDsig)

                    n, e = (crypto.decode_mpi(base64.b64decode(
                            keyvalue.getTagData(x))) for x in ('Modulus', 'Exponent'))
                    eir_pubkey = RSA.construct((n, long(e)))

                    pubkey_o = nbxmpp.c14n.c14n(keyvalue, self._is_buggy_gajim())
                else:
                    # FIXME DSA, etc.
                    raise NotImplementedError()

            enc_sig = parsed.getTag(name='SignatureValue',
                    namespace=XmlDsig).getData()
            signature = (crypto.decode_mpi(base64.b64decode(enc_sig)), )
        else:
            mac_o = self.decrypt(id_o)
            pubkey_o = ''

        c7l_form = self.c7lize_mac_id(form)

        content = self.n_s + self.n_o + crypto.encode_mpi(dh_i) + pubkey_o

        if sigmai:
            self.form_o = c7l_form
            content += self.form_o
        else:
            form_o2 = c7l_form
            content += self.form_o + form_o2

        mac_o_calculated = self.hmac(self.ks_o, content)

        if self.negotiated['recv_pubkey']:
            hash_ = crypto.sha256(mac_o_calculated)

            if not eir_pubkey.verify(hash_, signature):
                raise NegotiationError('public key signature verification failed!')

        elif mac_o_calculated != mac_o:
            raise NegotiationError('calculated mac_%s differs from received mac_%s'
                    % (i_o, i_o))
Example #9
0
    def accept_e2e_bob(self, form):
        response = xmpp.Message()

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

        x = xmpp.DataForm(typ="result")

        for field in ("nonce", "dhkeys", "rshashes", "identity", "mac"):
            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 exceptions.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 = ""

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

        for (secret, verified) in srses:
            if self.hmac(self.n_o, secret) in rshashes:
                srs = secret
                break

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

        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, "Shared Retained Secret")
        else:
            srshash = crypto.random_bytes(32)

        x.addChild(node=xmpp.DataField(name="FORM_TYPE", value="urn:xmpp:ssn"))
        x.addChild(node=xmpp.DataField(name="nonce", value=base64.b64encode(self.n_o)))
        x.addChild(node=xmpp.DataField(name="srshash", value=base64.b64encode(srshash)))

        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()
Example #10
0
    def accept_e2e_alice(self, form, negotiated):
        self.encryptable_stanzas = ["message"]
        self.sas_algs = "sas28x5"
        self.cipher = AES
        self.hash_alg = SHA256
        self.compression = None

        self.negotiated = negotiated

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

        result = xmpp.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=xmpp.DataField(name="FORM_TYPE", value="urn:xmpp:ssn"))
        result.addChild(node=xmpp.DataField(name="accept", value="1"))
        result.addChild(node=xmpp.DataField(name="nonce", value=base64.b64encode(self.n_o)))

        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) for (rs, v) 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) for rshash in rshashes]
            result.addChild(node=xmpp.DataField(name="rshashes", value=rshashes))
            result.addChild(node=xmpp.DataField(name="dhkeys", value=base64.b64encode(crypto.encode_mpi(e))))

            self.form_o = "".join(map(lambda el: xmpp.c14n.c14n(el), 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"
Example #11
0
    def respond_e2e_bob(self, form, negotiated, not_acceptable):
        response = xmpp.Message()
        feature = response.NT.feature
        feature.setNamespace(xmpp.NS_FEATURE)

        x = xmpp.DataForm(typ="submit")

        x.addChild(node=xmpp.DataField(name="FORM_TYPE", value="urn:xmpp:ssn"))
        x.addChild(node=xmpp.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=xmpp.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
        self.modp = int(form.getField("modp").getOptions()[group_order][1])
        x.addChild(node=xmpp.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 = form.getField("dhhashes").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])
            x.addChild(node=xmpp.DataField(name=name, value=b64ed))

        self.form_o = "".join(map(lambda el: xmpp.c14n.c14n(el), form.getChildren()))
        self.form_s = "".join(map(lambda el: xmpp.c14n.c14n(el), x.getChildren()))

        self.status = "responded-e2e"

        feature.addChild(node=x)

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

            feature = xmpp.Node(xmpp.NS_FEATURE + " feature")

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

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

        self.send(response)
Example #12
0
    def verify_identity(self, form, dh_i, sigmai, i_o):
        m_o = base64.b64decode(form["mac"])
        id_o = base64.b64decode(form["identity"])

        m_o_calculated = self.hmac(self.km_o, crypto.encode_mpi(self.c_o) + id_o)

        if m_o_calculated != m_o:
            raise exceptions.NegotiationError, "calculated m_%s differs from received m_%s" % (i_o, i_o)

        if i_o == "a" and self.sas_algs == "sas28x5":
            # we don't need to calculate this if there's a verified retained secret
            # (but we do anyways)
            self.sas = crypto.sas_28x5(m_o, self.form_s)

        if self.negotiated["recv_pubkey"]:
            plaintext = self.decrypt(id_o)
            parsed = xmpp.Node(node="<node>" + plaintext + "</node>")

            if self.negotiated["recv_pubkey"] == "hash":
                fingerprint = parsed.getTagData("fingerprint")

                # XXX find stored pubkey or terminate session
                raise "unimplemented"
            else:
                if self.negotiated["sign_algs"] == (XmlDsig + "rsa-sha256"):
                    keyvalue = parsed.getTag(name="RSAKeyValue", namespace=XmlDsig)

                    n, e = map(
                        lambda x: crypto.decode_mpi(base64.b64decode(keyvalue.getTagData(x))), ("Modulus", "Exponent")
                    )
                    eir_pubkey = RSA.construct((n, long(e)))

                    pubkey_o = xmpp.c14n.c14n(keyvalue)
                else:
                    # XXX DSA, etc.
                    raise "unimplemented"

            enc_sig = parsed.getTag(name="SignatureValue", namespace=XmlDsig).getData()
            signature = (crypto.decode_mpi(base64.b64decode(enc_sig)),)
        else:
            mac_o = self.decrypt(id_o)
            pubkey_o = ""

        c7l_form = self.c7lize_mac_id(form)

        content = self.n_s + self.n_o + crypto.encode_mpi(dh_i) + pubkey_o

        if sigmai:
            self.form_o = c7l_form
            content += self.form_o
        else:
            form_o2 = c7l_form
            content += self.form_o + form_o2

        mac_o_calculated = self.hmac(self.ks_o, content)

        if self.negotiated["recv_pubkey"]:
            hash = crypto.sha256(mac_o_calculated)

            if not eir_pubkey.verify(hash, signature):
                raise exceptions.NegotiationError, "public key signature verification failed!"

        elif mac_o_calculated != mac_o:
            raise exceptions.NegotiationError, "calculated mac_%s differs from received mac_%s" % (i_o, i_o)