commit 52edd22ca10d559270ee240409447351bd8639f8 Author: Damian Johnson atagar@torproject.org Date: Sat Aug 25 13:32:07 2018 -0700
Stub minimal cell decryption function
Ok, now into the meat of this sucker. Dave's branch introduces nice additions such as validating our backward digest and a flag to indicate if we've fully decrypted the cell or not.
For the moment moving to a minimal decryption function that only supports what we did previously. Next gonna try to integrate his new features to make a hybrid approach that hopefully takes the best of both. --- stem/client/__init__.py | 22 +++++++--------------- stem/client/cell.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 15 deletions(-)
diff --git a/stem/client/__init__.py b/stem/client/__init__.py index a216696a..19528d67 100644 --- a/stem/client/__init__.py +++ b/stem/client/__init__.py @@ -33,7 +33,7 @@ import stem.client.cell import stem.socket import stem.util.connection
-from stem.client.datatype import ZERO, LinkProtocol, Address, KDF +from stem.client.datatype import ZERO, LinkProtocol, Address, KDF, split
__all__ = [ 'cell', @@ -253,22 +253,14 @@ class Circuit(object): raise stem.ProtocolError('Circuit response should be a series of RELAY cells, but received an unexpected size for a response: %i' % len(reply))
while reply: - raw_cell, reply = stem.client.cell.Cell.pop(reply, self.relay.link_protocol) + encrypted_cell, reply = split(reply, self.relay.link_protocol.fixed_cell_length) + decrypted_cell, backward_key, backward_digest = stem.client.cell.RelayCell.decrypt(encrypted_cell, self.backward_key, self.backward_digest)
- if raw_cell.VALUE != stem.client.cell.RelayCell.VALUE: - raise stem.ProtocolError('RELAY cell responses should be %i but was %i' % (stem.client.cell.RelayCell.VALUE, raw_cell.VALUE)) - elif raw_cell.circ_id != self.id: - raise stem.ProtocolError('Response should be for circuit id %i, not %i' % (self.id, raw_cell.circ_id)) + if self.id != decrypted_cell.circ_id: + raise stem.ProtocolError('Response should be for circuit id %i, not %i' % (self.id, decrypted_cell.circ_id))
- decrypted_cell, fully_decrypted, new_backward_digest, new_backward_key = raw_cell.decrypt(self.backward_digest, self.backward_key, interpret = True) - - if not fully_decrypted: - raise stem.ProtocolError('Response for circuit id %i was not fully decrypted, when expected to be' % self.id) - - # Again, if the above raises the digest/key should remain unchanged. - - self.backward_digest = new_backward_digest - self.backward_key = new_backward_key + self.backward_digest = backward_digest + self.backward_key = backward_key
reply_cells.append(decrypted_cell)
diff --git a/stem/client/cell.py b/stem/client/cell.py index 6587ebb5..3de1c731 100644 --- a/stem/client/cell.py +++ b/stem/client/cell.py @@ -551,6 +551,36 @@ class RelayCell(CircuitCell): elif stream_id and self.command in STREAM_ID_DISALLOWED: raise ValueError('%s relay cells concern the circuit itself and cannot have a stream id' % self.command)
+ @classmethod + def decrypt(link_protocol, content, digest, key): + """ + Parse the given content as an encrypted RELAY cell. + """ + + # TODO: Fill in the above pydocs, deduplicate with the other decrypt + # method, yadda yadda. Starting with a minimal stub to see if this makes + # the Circuit class better. I'll circle back to clean up this module if it + # works. + + if len(content) != link_protocol.fixed_cell_length: + raise stem.ProtocolError('RELAY cells should be %i bytes, but received %i' % (link_protocol.fixed_cell_length, len(content))) + + circ_id, content = link_protocol.circ_id_size.pop(content) + command, payload = Size.CHAR.pop(content) + + if command != RelayCell.VALUE: + raise stem.ProtocolError('Cannot decrypt as a RELAY cell. This had command %i instead.' % command) + + key = copy.copy(key) + decrypted = key.update(payload) + + # TODO: Integrate with check_digest() and flag for integrating if we're + # fully decrypted. For the moment we only handle direct responses (ie. all + # the cells we receive can be fully decrypted) but if we attempt to support + # relaying we'll need to pass along cells we can only partially decrypt. + + return RelayCell._unpack(decrypted, circ_id, link_protocol), key, digest + @staticmethod def _coerce_digest(digest): """
tor-commits@lists.torproject.org