Exemplo n.º 1
0
def parse_bob_data(stanza):
    data_node = stanza.getTag('data', namespace=Namespace.BOB)
    if data_node is None:
        return None

    cid = data_node.getAttr('cid')
    type_ = data_node.getAttr('type')
    max_age = data_node.getAttr('max-age')
    if max_age is not None:
        try:
            max_age = int(max_age)
        except Exception:
            log.exception(stanza)
            return None

    if cid is None or type_ is None:
        log.warning('Invalid data node (no cid or type attr): %s', stanza)
        return None

    try:
        algo_hash = cid.split('@')[0]
        algo, hash_ = algo_hash.split('+')
    except Exception:
        log.exception('Invalid cid: %s', stanza)
        return None

    bob_data = data_node.getData()
    if not bob_data:
        log.warning('No bob data found: %s', stanza)
        return None

    try:
        bob_data = b64decode(bob_data, return_type=bytes)
    except Exception:
        log.warning('Unable to decode data')
        log.exception(stanza)
        return None

    try:
        sha = hashlib.new(algo)
    except ValueError as error:
        log.warning(stanza)
        log.warning(error)
        return None

    sha.update(bob_data)
    if sha.hexdigest() != hash_:
        log.warning('Invalid hash: %s', stanza)
        return None

    return BobData(algo=algo,
                   hash_=hash_,
                   max_age=max_age,
                   data=bob_data,
                   cid=cid,
                   type=type_)
Exemplo n.º 2
0
    def response(self, server_first_message):
        server_first_message = b64decode(server_first_message)
        challenge = self._scram_parse(server_first_message)

        client_nonce = challenge['r'][:self.nonce_length]
        if client_nonce != self._client_nonce:
            raise AuthFail('Invalid client nonce received from server')

        salt = b64decode(challenge['s'], bytes)
        iteration_count = int(challenge['i'])

        if iteration_count < 4096:
            raise AuthFail('Salt iteration count to low: %s' % iteration_count)

        salted_password = pbkdf2_hmac(self._hash_method,
                                      self._password.encode('utf8'), salt,
                                      iteration_count)

        client_final_message_wo_proof = 'c=%s,r=%s' % (
            self._b64_channel_binding_data, challenge['r'])

        client_key = self._hmac(salted_password, 'Client Key')
        stored_key = self._h(client_key)
        auth_message = '%s,%s,%s' % (self._client_first_message_bare,
                                     server_first_message,
                                     client_final_message_wo_proof)
        client_signature = self._hmac(stored_key, auth_message)
        client_proof = self._xor(client_key, client_signature)

        client_finale_message = 'c=%s,r=%s,p=%s' % (
            self._b64_channel_binding_data, challenge['r'],
            b64encode(client_proof))

        server_key = self._hmac(salted_password, 'Server Key')
        self._server_signature = self._hmac(server_key, auth_message)

        payload = b64encode(client_finale_message)
        node = Node('response',
                    attrs={'xmlns': Namespace.SASL},
                    payload=[payload])
        self._client.send_nonza(node)
Exemplo n.º 3
0
    def get_avatar(self):
        try:
            avatar = self.data['PHOTO']['BINVAL']
        except Exception:
            return None, None

        if not avatar:
            return None, None

        avatar = b64decode(avatar, return_type=bytes)
        avatar_sha = hashlib.sha1(avatar).hexdigest()
        return avatar, avatar_sha
Exemplo n.º 4
0
def _parse_secret_key(item):
    sec_key = item.getTag('secretkey', namespace=Namespace.OPENPGP)
    if sec_key is None:
        raise ValueError('secretkey node missing')

    data = sec_key.getData()
    if not data:
        raise ValueError('secretkey data missing')

    try:
        key = b64decode(data, return_type=bytes)
    except Exception as error:
        raise ValueError(f'decoding error: {error}')

    return key
Exemplo n.º 5
0
def _parse_public_key(jid, item):
    pub_key = item.getTag('pubkey', namespace=Namespace.OPENPGP)
    if pub_key is None:
        raise ValueError('pubkey node missing')

    date = parse_datetime(pub_key.getAttr('date'), epoch=True)

    data = pub_key.getTag('data')
    if data is None:
        raise ValueError('data node missing')

    try:
        key = b64decode(data.getData(), return_type=bytes)
    except Exception as error:
        raise ValueError(f'decoding error: {error}')

    return PGPPublicKey(jid, key, date)
Exemplo n.º 6
0
 def response(self, server_message, *args, **kwargs):
     server_message = b64decode(server_message, bytes)
     try:
         if not self.ctx.complete:
             output_token = self.ctx.step(server_message)
         else:
             result = self.ctx.unwrap(server_message)
             # TODO(jelmer): Log result.message
             data = b'\x00\x00\x00\x00' + bytes(self.ctx.initiator_name)
             output_token = self.ctx.wrap(data, False).message
     except (gssapi.exceptions.GeneralError, gssapi.raw.misc.GSSError) as e:
         raise AuthFail(e)
     response = b64encode(output_token)
     node = Node('response',
                 attrs={'xmlns': Namespace.SASL},
                 payload=response)
     self._client.send_nonza(node)
Exemplo n.º 7
0
def _get_avatar_data(item, id_):
    data_node = item.getTag('data', namespace=Namespace.AVATAR_DATA)
    if data_node is None:
        raise MalformedStanzaError('data node missing', item)

    data = data_node.getData()
    if not data:
        raise MalformedStanzaError('data node empty', item)

    try:
        avatar = b64decode(data, return_type=bytes)
    except Exception as error:
        raise MalformedStanzaError(f'decoding error: {error}', item)

    avatar_sha = hashlib.sha1(avatar).hexdigest()
    if avatar_sha != id_:
        raise MalformedStanzaError(f'avatar does not match sha', item)

    return AvatarData(data=avatar, sha=avatar_sha)
Exemplo n.º 8
0
    def _process_openpgp_message(self, _client, stanza, properties):
        openpgp = stanza.getTag('openpgp', namespace=Namespace.OPENPGP)
        if openpgp is None:
            self._log.warning('No openpgp node found')
            self._log.warning(stanza)
            return

        data = openpgp.getData()
        if not data:
            self._log.warning('No data in openpgp node found')
            self._log.warning(stanza)
            return

        self._log.info('Encrypted message received')
        try:
            properties.openpgp = b64decode(data, return_type=bytes)
        except Exception:
            self._log.warning('b64decode failed')
            self._log.warning(stanza)
            return
Exemplo n.º 9
0
 def success(self, server_last_message):
     server_last_message = b64decode(server_last_message)
     success = self._scram_parse(server_last_message)
     server_signature = b64decode(success['v'], bytes)
     if server_signature != self._server_signature:
         raise AuthFail('Invalid server signature')
Exemplo n.º 10
0
def _parse_bundle(item):
    '''
    <item id='current'>
      <bundle xmlns='eu.siacs.conversations.axolotl'>
        <signedPreKeyPublic signedPreKeyId='1'>
          BASE64ENCODED...
        </signedPreKeyPublic>
        <signedPreKeySignature>
          BASE64ENCODED...
        </signedPreKeySignature>
        <identityKey>
          BASE64ENCODED...
        </identityKey>
        <prekeys>
          <preKeyPublic preKeyId='1'>
            BASE64ENCODED...
          </preKeyPublic>
          <preKeyPublic preKeyId='2'>
           BASE64ENCODED...
          </preKeyPublic>
          <preKeyPublic preKeyId='3'>
            BASE64ENCODED...
          </preKeyPublic>
          <!-- ... -->
        </prekeys>
      </bundle>
    </item>
    '''
    if item is None:
        raise MalformedStanzaError('No item in node found', item)

    bundle = item.getTag('bundle', namespace=Namespace.OMEMO_TEMP)
    if bundle is None:
        raise MalformedStanzaError('No bundle node found', item)

    result = {}
    signed_prekey_node = bundle.getTag('signedPreKeyPublic')
    try:
        result['spk'] = {'key': b64decode(signed_prekey_node.getData(), bytes)}
    except Exception as error:
        error = 'Failed to decode signedPreKeyPublic: %s' % error
        raise MalformedStanzaError(error, item)

    signed_prekey_id = signed_prekey_node.getAttr('signedPreKeyId')
    try:
        result['spk']['id'] = int(signed_prekey_id)
    except Exception as error:
        raise MalformedStanzaError('Invalid signedPreKeyId: %s' % error, item)

    signed_signature_node = bundle.getTag('signedPreKeySignature')
    try:
        result['spk_signature'] = b64decode(signed_signature_node.getData(),
                                            bytes)
    except Exception as error:
        error = 'Failed to decode signedPreKeySignature: %s' % error
        raise MalformedStanzaError(error, item)

    identity_key_node = bundle.getTag('identityKey')
    try:
        result['ik'] = b64decode(identity_key_node.getData(), bytes)
    except Exception as error:
        error = 'Failed to decode IdentityKey: %s' % error
        raise MalformedStanzaError(error, item)

    prekeys = bundle.getTag('prekeys')
    if prekeys is None or not prekeys.getChildren():
        raise MalformedStanzaError('No prekeys node found', item)

    result['otpks'] = []
    for prekey in prekeys.getChildren():
        try:
            id_ = int(prekey.getAttr('preKeyId'))
        except Exception as error:
            raise MalformedStanzaError('Invalid prekey: %s' % error, item)

        try:
            key = b64decode(prekey.getData(), bytes)
        except Exception as error:
            raise MalformedStanzaError(
                'Failed to decode preKeyPublic: %s' % error, item)

        result['otpks'].append({'key': key, 'id': id_})

    return OMEMOBundle(**result)
Exemplo n.º 11
0
def _parse_omemo_message(stanza):
    '''
    <message>
      <encrypted xmlns='eu.siacs.conversations.axolotl'>
        <header sid='27183'>
          <key rid='31415'>BASE64ENCODED...</key>
          <key prekey="true" rid='12321'>BASE64ENCODED...</key>
          <!-- ... -->
          <iv>BASE64ENCODED...</iv>
        </header>
        <payload>BASE64ENCODED</payload>
      </encrypted>
      <store xmlns='urn:xmpp:hints'/>
    </message>
    '''
    encrypted = stanza.getTag('encrypted', namespace=Namespace.OMEMO_TEMP)
    if encrypted is None:
        raise MalformedStanzaError('No encrypted node found', stanza)

    header = encrypted.getTag('header')
    if header is None:
        raise MalformedStanzaError('header node not found', stanza)

    try:
        sid = int(header.getAttr('sid'))
    except Exception as error:
        raise MalformedStanzaError('sid attr not found', stanza)

    iv_node = header.getTag('iv')
    try:
        iv = b64decode(iv_node.getData(), bytes)
    except Exception as error:
        raise MalformedStanzaError('failed to decode iv: %s' % error, stanza)

    payload = None
    payload_node = encrypted.getTag('payload')
    if payload_node is not None:
        try:
            payload = b64decode(payload_node.getData(), bytes)
        except Exception as error:
            raise MalformedStanzaError('failed to decode payload: %s' % error,
                                       stanza)

    key_nodes = header.getTags('key')
    if not key_nodes:
        raise MalformedStanzaError('no keys found', stanza)

    keys = {}
    for kn in key_nodes:
        rid = kn.getAttr('rid')
        if rid is None:
            raise MalformedStanzaError('rid not found', stanza)

        prekey = kn.getAttr('prekey')
        if prekey is None:
            prekey = False
        else:
            try:
                prekey = from_xs_boolean(prekey)
            except ValueError as error:
                raise MalformedStanzaError(error, stanza)

        try:
            keys[int(rid)] = (b64decode(kn.getData(), bytes), prekey)
        except Exception as error:
            raise MalformedStanzaError('failed to decode key: %s' % error,
                                       stanza)

    return OMEMOMessage(sid=sid, iv=iv, keys=keys, payload=payload)