[tor-commits] [obfsproxy/master] Improve packet morphing algorithm.

asn at torproject.org asn at torproject.org
Tue Jul 15 12:23:07 UTC 2014


commit 0806a87f0183b3b74d20fe99184bdfb361d5f443
Author: Philipp Winter <phw at torproject.org>
Date:   Mon Mar 10 18:47:15 2014 +0100

    Improve packet morphing algorithm.
    
    We only want to run the packet morphing algorithm when we really need
    it -- which is immediately before we send data.  Previously, we would morph
    immediately upon receiving data which is not optimal.
    
    This should fix <https://bugs.torproject.org/10991>.  Thanks to Yawning Angel
    who pointed out the problem.
---
 obfsproxy/transports/scramblesuit/packetmorpher.py |   37 +++++++++++++++++---
 obfsproxy/transports/scramblesuit/scramblesuit.py  |   31 +++++++---------
 2 files changed, 44 insertions(+), 24 deletions(-)

diff --git a/obfsproxy/transports/scramblesuit/packetmorpher.py b/obfsproxy/transports/scramblesuit/packetmorpher.py
index 4a72f0b..081d7dc 100644
--- a/obfsproxy/transports/scramblesuit/packetmorpher.py
+++ b/obfsproxy/transports/scramblesuit/packetmorpher.py
@@ -8,6 +8,7 @@ morphed network data should then match the probability distribution.
 
 import random
 
+import message
 import probdist
 import const
 
@@ -39,14 +40,37 @@ class PacketMorpher( object ):
             self.dist = probdist.new(lambda: random.randint(const.HDR_LENGTH,
                                                             const.MTU))
 
+    def getPadding( self, sendCrypter, sendHMAC, dataLen ):
+        """
+        Based on the burst's size, return a ready-to-send padding blurb.
+        """
+
+        padLen = self.calcPadding(dataLen)
+
+        assert const.HDR_LENGTH <= padLen < (const.MTU + const.HDR_LENGTH), \
+               "Invalid padding length %d." % padLen
+
+        # We have to use two padding messages if the padding is > MTU.
+        if padLen > const.MTU:
+            padMsgs = [message.new("", paddingLen=700 - const.HDR_LENGTH),
+                       message.new("", paddingLen=padLen - 700 - \
+                                       const.HDR_LENGTH)]
+        else:
+            padMsgs = [message.new("", paddingLen=padLen - const.HDR_LENGTH)]
+
+        blurbs = [msg.encryptAndHMAC(sendCrypter, sendHMAC) for msg in padMsgs]
+
+        return "".join(blurbs)
+
     def calcPadding( self, dataLen ):
         """
-        Based on `dataLen', determines the padding for a network packet.
+        Based on `dataLen', determine and return a burst's padding.
 
-        ScrambleSuit morphs packets which are smaller than the link's MTU.
-        This method draws a random sample from the probability distribution
-        which is used to determine and return the padding for such packets.
-        This effectively gets rid of Tor's 586-byte signature.
+        ScrambleSuit morphs the last packet in a burst, i.e., packets which
+        don't fill the link's MTU.  This is done by drawing a random sample
+        from our probability distribution which is used to determine and return
+        the padding for such packets.  This effectively gets rid of Tor's
+        586-byte signature.
         """
 
         # The `is' and `should-be' length of the burst's last packet.
@@ -59,6 +83,9 @@ class PacketMorpher( object ):
         else:
             padLen = (const.MTU - dataLen) + sampleLen
 
+        if padLen < const.HDR_LENGTH:
+            padLen += const.MTU
+
         log.debug("Morphing the last %d-byte packet to %d bytes by adding %d "
                   "bytes of padding." %
                   (dataLen % const.MTU, sampleLen, padLen))
diff --git a/obfsproxy/transports/scramblesuit/scramblesuit.py b/obfsproxy/transports/scramblesuit/scramblesuit.py
index 8e04cc5..43b52b5 100644
--- a/obfsproxy/transports/scramblesuit/scramblesuit.py
+++ b/obfsproxy/transports/scramblesuit/scramblesuit.py
@@ -234,27 +234,12 @@ class ScrambleSuitTransport( base.BaseTransport ):
 
         # Wrap the application's data in ScrambleSuit protocol messages.
         messages = message.createProtocolMessages(data, flags=flags)
-
-        # Let the packet morpher tell us how much we should pad.
-        paddingLen = self.pktMorpher.calcPadding(sum([len(msg) for
-                                                 msg in messages]))
-
-        # If padding > header length, a single message will do...
-        if paddingLen > const.HDR_LENGTH:
-            messages.append(message.new("", paddingLen=paddingLen -
-                                                       const.HDR_LENGTH))
-
-        # ...otherwise, we use two padding-only messages.
-        else:
-            messages.append(message.new("", paddingLen=const.MPU -
-                                                       const.HDR_LENGTH))
-            messages.append(message.new("", paddingLen=paddingLen))
-
         blurb = "".join([msg.encryptAndHMAC(self.sendCrypter,
                         self.sendHMAC) for msg in messages])
 
-        # Flush data chunk for chunk to obfuscate inter arrival times.
+        # Flush data chunk for chunk to obfuscate inter-arrival times.
         if const.USE_IAT_OBFUSCATION:
+
             if len(self.choppingBuf) == 0:
                 self.choppingBuf.write(blurb)
                 reactor.callLater(self.iatMorpher.randomSample(),
@@ -262,8 +247,12 @@ class ScrambleSuitTransport( base.BaseTransport ):
             else:
                 # flushPieces() is still busy processing the chopping buffer.
                 self.choppingBuf.write(blurb)
+
         else:
-            self.circuit.downstream.write(blurb)
+            padBlurb = self.pktMorpher.getPadding(self.sendCrypter,
+                                                  self.sendHMAC,
+                                                  len(blurb))
+            self.circuit.downstream.write(blurb + padBlurb)
 
     def flushPieces( self ):
         """
@@ -283,7 +272,11 @@ class ScrambleSuitTransport( base.BaseTransport ):
 
         # Drain and send whatever is left in the output buffer.
         else:
-            self.circuit.downstream.write(self.choppingBuf.read())
+            blurb = self.choppingBuf.read()
+            padBlurb = self.pktMorpher.getPadding(self.sendCrypter,
+                                                  self.sendHMAC,
+                                                  len(blurb))
+            self.circuit.downstream.write(blurb + padBlurb)
             return
 
         reactor.callLater(self.iatMorpher.randomSample(), self.flushPieces)





More information about the tor-commits mailing list