[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [stem/master] Support CREATE_FAST and CREATED_FAST cells
commit 32188dd28f20170f8d2b2dd1da73e29b47bac1a2
Author: Damian Johnson <atagar@xxxxxxxxxxxxxx>
Date: Sun Jan 21 20:24:35 2018 -0800
Support CREATE_FAST and CREATED_FAST cells
---
stem/client/cell.py | 125 ++++++++++++++++++++++++++++++++++++++---------
test/unit/client/cell.py | 31 ++++++++++++
2 files changed, 133 insertions(+), 23 deletions(-)
diff --git a/stem/client/cell.py b/stem/client/cell.py
index 3a596b9c..6f107b79 100644
--- a/stem/client/cell.py
+++ b/stem/client/cell.py
@@ -49,6 +49,7 @@ from stem.util import _hash_attr, datetime_to_unix
FIXED_PAYLOAD_LEN = 509
AUTH_CHALLENGE_SIZE = 32
+HASH_LEN = 20
class Cell(object):
@@ -120,7 +121,7 @@ class Cell(object):
raise ValueError('%s cell should have a payload of %i bytes, but only had %i' % (cls.NAME, payload_len, len(content)))
payload, content = split(content, payload_len)
- return cls._unpack(payload, link_version, circ_id), content
+ return cls._unpack(payload, circ_id, link_version), content
@classmethod
def _pack(cls, link_version, payload, circ_id = 0):
@@ -144,6 +145,15 @@ class Cell(object):
:raise: **ValueError** if cell type invalid or payload is too large
"""
+ if isinstance(cls, CircuitCell) and circ_id is None:
+ if cls.NAME.startswith('CREATE'):
+ # Since we're initiating the circuit we pick any value from a range
+ # that's determined by our link version.
+
+ circ_id = 0x80000000 if link_version > 3 else 0x01
+ else:
+ raise ValueError('%s cells require a circ_id' % cls.NAME)
+
cell = io.BytesIO()
cell.write(Size.LONG.pack(circ_id) if link_version > 3 else Size.SHORT.pack(circ_id))
cell.write(Size.CHAR.pack(cls.VALUE))
@@ -189,30 +199,12 @@ class Cell(object):
class CircuitCell(Cell):
"""
Cell concerning circuits.
- """
-
- @classmethod
- def _pack(cls, link_version, payload, circ_id):
- """
- Provides bytes that can be used on the wire for these cell attributes.
-
- :param str name: cell command
- :param int link_version: link protocol version
- :param bytes payload: cell payload
- :param int circ_id: circuit id
-
- :raise: **ValueError** if cell type invalid or payload is too large
- """
-
- if circ_id is None and cls.NAME.startswith('CREATE'):
- # Since we're initiating the circuit we pick any value from a range
- # that's determined by our link version.
- circ_id = 0x80000000 if link_version > 3 else 0x01
- else:
- raise ValueError('%s cells require a circ_id' % cls.NAME)
+ :var int circ_id: circuit id
+ """
- return Cell._pack(link_version, payload, circ_id)
+ def __init__(self, circ_id):
+ self.circ_id = circ_id
class PaddingCell(Cell):
@@ -275,16 +267,103 @@ class DestroyCell(CircuitCell):
class CreateFastCell(CircuitCell):
+ """
+ Create a circuit with our first hop. This is lighter weight than further hops
+ because we've already established the relay's identity and secret key.
+
+ :var bytes key_material: randomized key material
+ """
+
NAME = 'CREATE_FAST'
VALUE = 5
IS_FIXED_SIZE = True
+ def __init__(self, circ_id, key_material):
+ super(CreateFastCell, self).__init__(circ_id)
+ self.key_material = key_material
+
+ @classmethod
+ def pack(cls, link_version, circ_id, key_material = None):
+ """
+ Provides a randomized circuit construction payload.
+
+ :param int link_version: link protocol version
+ :param int circ_id: circuit id
+ :param bytes key_material: randomized key material
+
+ :returns: **bytes** with our randomized key material
+ """
+
+ if key_material and len(key_material) != HASH_LEN:
+ raise ValueError('Key material should be %i bytes, but was %i' % (HASH_LEN, len(key_material)))
+
+ return cls._pack(link_version, key_material if key_material else os.urandom(HASH_LEN), circ_id)
+
+ @classmethod
+ def _unpack(cls, content, circ_id, link_version):
+ content = content.rstrip(ZERO)
+
+ if len(content) != HASH_LEN:
+ raise ValueError('Key material should be %i bytes, but was %i' % (HASH_LEN, len(content)))
+
+ return CreateFastCell(circ_id, content)
+
+ def __hash__(self):
+ return _hash_attr(self, 'key_material')
+
class CreatedFastCell(CircuitCell):
+ """
+ CREATE_FAST reply.
+
+ :var bytes key_material: randomized key material
+ :var bytes derivative_key: hash proving the relay knows our shared key
+ """
+
NAME = 'CREATED_FAST'
VALUE = 6
IS_FIXED_SIZE = True
+ def __init__(self, circ_id, key_material, derivative_key):
+ super(CreatedFastCell, self).__init__(circ_id)
+ self.key_material = key_material
+ self.derivative_key = derivative_key
+
+ @classmethod
+ def pack(cls, link_version, circ_id, derivative_key, key_material = None):
+ """
+ Provides a randomized circuit construction payload.
+
+ :param int link_version: link protocol version
+ :param int circ_id: circuit id
+ :param bytes derivative_key: hash proving the relay knows our shared key
+ :param bytes key_material: randomized key material
+
+ :returns: **bytes** with our randomized key material
+ """
+
+ if key_material and len(key_material) != HASH_LEN:
+ raise ValueError('Key material should be %i bytes, but was %i' % (HASH_LEN, len(key_material)))
+ elif len(derivative_key) != HASH_LEN:
+ raise ValueError('Derivatived key should be %i bytes, but was %i' % (HASH_LEN, len(derivative_key)))
+
+ if not key_material:
+ key_material = os.urandom(HASH_LEN)
+
+ return cls._pack(link_version, key_material + derivative_key, circ_id)
+
+ @classmethod
+ def _unpack(cls, content, circ_id, link_version):
+ content = content.rstrip(ZERO)
+
+ if len(content) != HASH_LEN * 2:
+ raise ValueError('Key material and derivatived key should be %i bytes, but was %i' % (HASH_LEN * 2, len(content)))
+
+ return CreatedFastCell(circ_id, content[:HASH_LEN], content[HASH_LEN:])
+
+ def __hash__(self):
+ return _hash_attr(self, 'derivative_key', 'key_material')
+
class VersionsCell(Cell):
"""
diff --git a/test/unit/client/cell.py b/test/unit/client/cell.py
index 22de54d9..577114c3 100644
--- a/test/unit/client/cell.py
+++ b/test/unit/client/cell.py
@@ -13,6 +13,8 @@ from stem.client.cell import (
FIXED_PAYLOAD_LEN,
Cell,
PaddingCell,
+ CreateFastCell,
+ CreatedFastCell,
VersionsCell,
NetinfoCell,
VPaddingCell,
@@ -27,6 +29,14 @@ PADDING_CELLS = {
'\x00\x00\x00' + RANDOM_PAYLOAD: RANDOM_PAYLOAD,
}
+CREATE_FAST_CELLS = {
+ ('\x80\x00\x00\x00\x05\x92O\x0c\xcb\xa8\xac\xfb\xc9\x7f\xd0\rz\x1a\x03u\x91\xceas\xce' + ZERO * 489): (2147483648, '\x92O\x0c\xcb\xa8\xac\xfb\xc9\x7f\xd0\rz\x1a\x03u\x91\xceas\xce'),
+}
+
+CREATED_FAST_CELLS = {
+ ('\x80\x00\x00\x00\x06\x92O\x0c\xcb\xa8\xac\xfb\xc9\x7f\xd0\rz\x1a\x03u\x91\xceas\xce\x13Z\x99\xb2\x1e\xb6\x05\x85\x17\xfc\x1c\x00{\xa9\xae\x83^K\x99\xb2' + ZERO * 469): (2147483648, '\x92O\x0c\xcb\xa8\xac\xfb\xc9\x7f\xd0\rz\x1a\x03u\x91\xceas\xce', '\x13Z\x99\xb2\x1e\xb6\x05\x85\x17\xfc\x1c\x00{\xa9\xae\x83^K\x99\xb2'),
+}
+
VERSIONS_CELLS = {
'\x00\x00\x07\x00\x00': [],
'\x00\x00\x07\x00\x02\x00\x01': [1],
@@ -118,6 +128,27 @@ class TestCell(unittest.TestCase):
self.assertEqual(cell_bytes, PaddingCell.pack(2, payload))
self.assertEqual(payload, Cell.unpack(cell_bytes, 2)[0].payload)
+ def test_create_fast(self):
+ for cell_bytes, (circ_id, key_material) in CREATE_FAST_CELLS.items():
+ self.assertEqual(cell_bytes, CreateFastCell.pack(5, circ_id, key_material))
+
+ cell = Cell.unpack(cell_bytes, 5)[0]
+ self.assertEqual(circ_id, cell.circ_id)
+ self.assertEqual(key_material, cell.key_material)
+
+ self.assertRaisesRegexp(ValueError, 'Key material should be 20 bytes, but was 3', CreateFastCell.pack, 2, 5, 'boo')
+
+ def test_created_fast(self):
+ for cell_bytes, (circ_id, key_material, derivative_key) in CREATED_FAST_CELLS.items():
+ self.assertEqual(cell_bytes, CreatedFastCell.pack(5, circ_id, derivative_key, key_material))
+
+ cell = Cell.unpack(cell_bytes, 5)[0]
+ self.assertEqual(circ_id, cell.circ_id)
+ self.assertEqual(key_material, cell.key_material)
+ self.assertEqual(derivative_key, cell.derivative_key)
+
+ self.assertRaisesRegexp(ValueError, 'Key material should be 20 bytes, but was 3', CreateFastCell.pack, 2, 5, 'boo')
+
def test_versions_packing(self):
for cell_bytes, versions in VERSIONS_CELLS.items():
self.assertEqual(cell_bytes, VersionsCell.pack(versions))
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits