[tor-commits] [stem/master] Initial Circuit.send() method
atagar at torproject.org
atagar at torproject.org
Wed Feb 7 19:44:51 UTC 2018
commit b6ec30d450e929976acf3fce9378f0c3a777d938
Author: Damian Johnson <atagar at torproject.org>
Date: Mon Feb 5 11:24:34 2018 -0800
Initial Circuit.send() method
Quite a few things I dislike about this, but it works! Next up: testing and
refinement...
---
stem/client/__init__.py | 37 ++++++++++++++++++++++++++++++++++++-
stem/client/cell.py | 17 +++++++++++++++--
2 files changed, 51 insertions(+), 3 deletions(-)
diff --git a/stem/client/__init__.py b/stem/client/__init__.py
index fdb436b6..4f9ed17c 100644
--- a/stem/client/__init__.py
+++ b/stem/client/__init__.py
@@ -19,6 +19,7 @@ a wrapper for :class:`~stem.socket.RelaySocket`, much the same way as
+- close - shuts down our connection
"""
+import copy
import hashlib
import stem
@@ -26,7 +27,7 @@ import stem.client.cell
import stem.socket
import stem.util.connection
-from stem.client.datatype import ZERO, AddrType, Address, KDF
+from stem.client.datatype import ZERO, AddrType, Address, KDF, split
__all__ = [
'cell',
@@ -207,3 +208,37 @@ class Circuit(object):
self.backward_digest = hashlib.sha1(kdf.backward_digest)
self.forward_key = Cipher(algorithms.AES(kdf.forward_key), ctr, default_backend()).encryptor()
self.backward_key = Cipher(algorithms.AES(kdf.backward_key), ctr, default_backend()).decryptor()
+
+ def send(self, command, data, stream_id = 0):
+ """
+ Sends a message over the circuit.
+
+ :param stem.client.RelayCommand command: command to be issued
+ :param bytes data: message payload
+ :param int stream_id: specific stream this concerns
+ """
+
+ # TODO: move RelayCommand to this base module?
+ # TODO: add lock
+
+ orig_digest = self.forward_digest.copy()
+ orig_key = copy.copy(self.forward_key)
+
+ try:
+ cell = stem.client.cell.RelayCell(self.id, command, data, 0, stream_id)
+ payload_without_digest = cell.pack(self.relay.link_protocol)[3:]
+ self.forward_digest.update(payload_without_digest)
+
+ cell = stem.client.cell.RelayCell(self.id, command, data, self.forward_digest, stream_id)
+ header, payload = split(cell.pack(self.relay.link_protocol), 3)
+ encrypted_payload = header + self.forward_key.update(payload)
+
+ self.relay._orport.send(encrypted_payload)
+ except:
+ self.forward_digest = orig_digest
+ self.forward_key = orig_key
+ raise
+
+ def close(self):
+ self.relay._orport.send(stem.client.cell.DestroyCell(self.id).pack(self.relay.link_protocol))
+ del self.relay._circuits[self.id]
diff --git a/stem/client/cell.py b/stem/client/cell.py
index 17f27202..c4a19940 100644
--- a/stem/client/cell.py
+++ b/stem/client/cell.py
@@ -307,7 +307,7 @@ class RelayCell(CircuitCell):
VALUE = 3
IS_FIXED_SIZE = True
- def __init__(self, circ_id, command, data, digest = 0, stream_id = 0):
+ def __init__(self, circ_id, command, data, digest = 0, stream_id = 0, raw_content = None):
if 'hashlib.HASH' in str(type(digest)):
# Unfortunately hashlib generates from a dynamic private class so
# isinstance() isn't such a great option.
@@ -325,6 +325,7 @@ class RelayCell(CircuitCell):
self.data = data
self.digest = digest
self.stream_id = stream_id
+ self._raw_content = raw_content
if not stream_id and self.command in STREAM_ID_REQUIRED:
raise ValueError('%s relay cells require a stream id' % self.command)
@@ -342,8 +343,20 @@ class RelayCell(CircuitCell):
return RelayCell._pack(link_protocol, payload.getvalue(), self.circ_id)
+ def decrypt(self, circ):
+ # TODO: clearly funky, just a spot to start...
+
+ if not self._raw_content:
+ raise ValueError('Only received cells can be decrypted')
+
+ decrypted = circ.backward_key.update(self._raw_content)
+ return RelayCell._unpack(decrypted, self.circ_id, 3)
+
+
@classmethod
def _unpack(cls, content, circ_id, link_protocol):
+ orig_content = content
+
command, content = Size.CHAR.pop(content)
_, content = Size.SHORT.pop(content) # 'recognized' field
stream_id, content = Size.SHORT.pop(content)
@@ -351,7 +364,7 @@ class RelayCell(CircuitCell):
data_len, content = Size.SHORT.pop(content)
data, content = split(content, data_len)
- return RelayCell(circ_id, command, data, digest, stream_id)
+ return RelayCell(circ_id, command, data, digest, stream_id, orig_content)
def __hash__(self):
return _hash_attr(self, 'command_int', 'stream_id', 'digest', 'data')
More information about the tor-commits
mailing list