[tor-commits] [stem/master] Implement PADDING and VPADDING cells

atagar at torproject.org atagar at torproject.org
Sun Jan 21 02:04:04 UTC 2018


commit 9fb787cd89b10254df58deb0d190ac5fdbe58c16
Author: Damian Johnson <atagar at torproject.org>
Date:   Sun Jan 14 13:06:00 2018 -0800

    Implement PADDING and VPADDING cells
    
    Couple particularly easy cell types.
---
 stem/client/cell.py      | 68 ++++++++++++++++++++++++++++++++++++++++++++++--
 test/unit/client/cell.py | 38 +++++++++++++++++++++++++--
 2 files changed, 102 insertions(+), 4 deletions(-)

diff --git a/stem/client/cell.py b/stem/client/cell.py
index 4fe7952e..995b482a 100644
--- a/stem/client/cell.py
+++ b/stem/client/cell.py
@@ -38,6 +38,8 @@ Messages communicated over a Tor relay's ORPort.
 
 import inspect
 import io
+import os
+import random
 import sys
 
 from stem import UNDEFINED
@@ -219,10 +221,36 @@ class CircuitCell(Cell):
 
 
 class PaddingCell(Cell):
+  """
+  Randomized content to either keep activity going on a circuit.
+
+  :var bytes payload: randomized payload
+  """
+
   NAME = 'PADDING'
   VALUE = 0
   IS_FIXED_SIZE = True
 
+  def __init__(self, payload):
+    self.payload = payload
+
+  @classmethod
+  def pack(cls, link_version, payload = None):
+    """
+    Provides a randomized padding payload.
+
+    :param int link_version: link protocol version
+    :param bytes payload: padding payload
+
+    :returns: **bytes** with randomized content
+    """
+
+    return cls._pack(link_version, payload if payload else os.urandom(FIXED_PAYLOAD_LEN))
+
+  @classmethod
+  def _unpack(cls, content, circ_id, link_version):
+    return PaddingCell(content)
+
 
 class CreateCell(CircuitCell):
   NAME = 'CREATE'
@@ -332,10 +360,46 @@ class PaddingNegotiateCell(Cell):
 
 
 class VPaddingCell(Cell):
+  """
+  Variable length randomized content to either keep activity going on a circuit.
+
+  :var bytes payload: randomized payload
+  """
+
   NAME = 'VPADDING'
   VALUE = 128
   IS_FIXED_SIZE = False
 
+  def __init__(self, payload):
+    self.payload = payload
+
+  @classmethod
+  def pack(cls, link_version, size = None, payload = None):
+    """
+    Provides a randomized padding payload. If no size or payload is provided
+    then this provides padding of an arbitrarily chosen size between 128-1024.
+
+    :param int link_version: link protocol version
+    :param int size: number of bytes to pad
+    :param bytes payload: padding payload
+
+    :returns: **bytes** with randomized content
+
+    :raises: **ValueError** if both a size and payload are provided, and they
+      mismatch
+    """
+
+    if payload is None:
+      payload = os.urandom(size) if size else os.urandom(random.randint(128, 1024))
+    elif size is not None and size != len(payload):
+      raise ValueError('VPaddingCell.pack caller specified both a size of %i bytes and payload of %i bytes' % (size, len(payload)))
+
+    return cls._pack(link_version, payload)
+
+  @classmethod
+  def _unpack(cls, content, circ_id, link_version):
+    return VPaddingCell(content)
+
 
 class CertsCell(Cell):
   """
@@ -352,12 +416,12 @@ class CertsCell(Cell):
     self.certificates = certs
 
   @classmethod
-  def pack(cls, certs, link_version):
+  def pack(cls, link_version, certs):
     """
     Provides the payload for a series of certificates.
 
-    :param list certs: series of :class:`~stem.client.Certificate` for the cell
     :param int link_version: link protocol version
+    :param list certs: series of :class:`~stem.client.Certificate` for the cell
 
     :returns: **bytes** with a payload for these versions
     """
diff --git a/test/unit/client/cell.py b/test/unit/client/cell.py
index b26549e2..0d2b677d 100644
--- a/test/unit/client/cell.py
+++ b/test/unit/client/cell.py
@@ -2,18 +2,40 @@
 Unit tests for the stem.client.cell.
 """
 
+import os
 import unittest
 
 from stem.client import Certificate
-from stem.client.cell import Cell, VersionsCell, CertsCell
 from test.unit.client import test_data
 
+from stem.client.cell import (
+  FIXED_PAYLOAD_LEN,
+  Cell,
+  PaddingCell,
+  VersionsCell,
+  VPaddingCell,
+  CertsCell,
+)
+
+RANDOM_PAYLOAD = os.urandom(FIXED_PAYLOAD_LEN)
+
+PADDING_CELLS = {
+  '\x00\x00\x00' + RANDOM_PAYLOAD: RANDOM_PAYLOAD,
+}
+
 VERSIONS_CELLS = {
   '\x00\x00\x07\x00\x00': [],
   '\x00\x00\x07\x00\x02\x00\x01': [1],
   '\x00\x00\x07\x00\x06\x00\x01\x00\x02\x00\x03': [1, 2, 3],
 }
 
+VPADDING_CELLS = {
+  '\x00\x00\x80\x00\x00': '',
+  '\x00\x00\x80\x00\x01\x08': '\x08',
+  '\x00\x00\x80\x00\x02\x08\x11': '\x08\x11',
+  '\x00\x00\x80\x01\xfd' + RANDOM_PAYLOAD: RANDOM_PAYLOAD,
+}
+
 CERTS_CELLS = {
   '\x00\x00\x81\x00\x01\x00': [],
   '\x00\x00\x81\x00\x04\x01\x01\x00\x00': [Certificate(type = 1, value = '')],
@@ -49,14 +71,26 @@ class TestCell(unittest.TestCase):
     # TODO: we need to support more cell types before we can test this
     self.assertRaisesRegexp(NotImplementedError, 'Unpacking not yet implemented for AUTH_CHALLENGE cells', Cell.unpack, test_data('new_link_cells'), 2)
 
+  def test_padding_packing(self):
+    for cell_bytes, payload in PADDING_CELLS.items():
+      self.assertEqual(cell_bytes, PaddingCell.pack(2, payload))
+      self.assertEqual(payload, Cell.unpack(cell_bytes, 2)[0].payload)
+
   def test_versions_packing(self):
     for cell_bytes, versions in VERSIONS_CELLS.items():
       self.assertEqual(cell_bytes, VersionsCell.pack(versions))
       self.assertEqual(versions, Cell.unpack(cell_bytes, 2)[0].versions)
 
+  def test_vpadding_packing(self):
+    for cell_bytes, payload in VPADDING_CELLS.items():
+      self.assertEqual(cell_bytes, VPaddingCell.pack(2, payload = payload))
+      self.assertEqual(payload, Cell.unpack(cell_bytes, 2)[0].payload)
+
+    self.assertRaisesRegexp(ValueError, 'VPaddingCell.pack caller specified both a size of 5 bytes and payload of 1 bytes', VPaddingCell.pack, 2, 5, '\x02')
+
   def test_certs_packing(self):
     for cell_bytes, certs in CERTS_CELLS.items():
-      self.assertEqual(cell_bytes, CertsCell.pack(certs, 2))
+      self.assertEqual(cell_bytes, CertsCell.pack(2, certs))
       self.assertEqual(certs, Cell.unpack(cell_bytes, 2)[0].certificates)
 
     # extra bytes after the last certificate should be ignored





More information about the tor-commits mailing list