[Pkg-privacy-commits] [obfsproxy] 21/353: Implemented obfs2 and refactored transports to use new API
Ximin Luo
infinity0 at moszumanska.debian.org
Sat Aug 22 13:01:34 UTC 2015
This is an automated email from the git hooks/post-receive script.
infinity0 pushed a commit to branch master
in repository obfsproxy.
commit 3fb18d7613199277c49e8e366549d33fdb992e01
Author: Brandon Wiley <brandon at blanu.net>
Date: Wed Aug 1 15:52:02 2012 -0500
Implemented obfs2 and refactored transports to use new API
---
src/obfsproxy/transports/base.py | 31 ++++++
src/obfsproxy/transports/dummy.py | 17 ++-
src/obfsproxy/transports/dust_transport.py | 67 ++++++-----
src/obfsproxy/transports/obfs2.py | 172 +++++++++++++++++++++++++++++
src/obfsproxy/transports/obfs3.py | 67 ++++++-----
5 files changed, 273 insertions(+), 81 deletions(-)
diff --git a/src/obfsproxy/transports/base.py b/src/obfsproxy/transports/base.py
new file mode 100644
index 0000000..e1feebf
--- /dev/null
+++ b/src/obfsproxy/transports/base.py
@@ -0,0 +1,31 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+class BaseDaemon:
+
+ def __init__(self, decodedSocket, encodedSocket):
+ self.decodedSocket=decodedSocket
+ self.encodedSocket=encodedSocket
+
+ def read(self, socket, data, maxlen):
+ remaining=maxlen-len(data)
+ return data+socket.read(remaining)
+
+ def checkTransition(self, data, maxlen, newState):
+ if len(data)==maxlen:
+ state=newState
+ return True
+ else:
+ return False
+
+ def start(self):
+ pass
+
+ def receivedDecoded(self):
+ pass
+
+ def receivedEncoded(self):
+ pass
+
+ def end(self):
+ pass
diff --git a/src/obfsproxy/transports/dummy.py b/src/obfsproxy/transports/dummy.py
index e1d9e51..f9086b6 100644
--- a/src/obfsproxy/transports/dummy.py
+++ b/src/obfsproxy/transports/dummy.py
@@ -1,20 +1,19 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
+from obfsproxy.transports.base import BaseDaemon
-class DummyDaemon:
- def __init__(self, client, server)
- pass
+class DummyDaemon(BaseDaemon):
+ def receivedDecoded(self):
+ data=self.decodedSocket.readAll()
+ self.encodedSocket.write(data)
- def encode(self, data):
- return data
-
- def decode(self, data):
- return data
+ def receivedEncoded(self):
+ data=self.encodedSocket.readAll()
+ self.decodedSocket.write(data)
class DummyClient(DummyDaemon:
pass
-
class DummyServer(DummyDaemon):
pass
diff --git a/src/obfsproxy/transports/dust_transport.py b/src/obfsproxy/transports/dust_transport.py
index 9ba511c..cd3a03a 100644
--- a/src/obfsproxy/transports/dust_transport.py
+++ b/src/obfsproxy/transports/dust_transport.py
@@ -9,55 +9,50 @@ STREAM=1
HANDSHAKE_SIZE=IV_SIZE+KEY_SIZE
-class DustDaemon:
+class DustDaemon(BaseDaemon):
+
+ def __init__(self, decodedSocket, encodedSocket):
+ BaseDaemon.__init__(self, decodedSocket, encodedSocket)
- def __init__(self, client, server):
- self.client=client
- self.server=server
self.state=HANDSHAKE_WRITE
- self.encodeBuffer=bytes('')
- self.decodeBuffer=bytes('')
self.ekeypair=createEphemeralKeypair()
+ self.epub=bytes('')
- def read(self, data, count):
- if data:
- self.decodeBuffer=self.decodeBuffer+data
- if len(self.decodeBuffer)>=count:
- data=self.decodeBuffer[:count]
- self.decodeBuffer=self.decodeBuffer[count:]
- return data
- else:
- return None
+ def start(self):
+ self.encodedSocket.write(self.ekeypair.public.bytes)
- def encode(self, data):
- if self.state==HANDSHAKE:
- self.encodeBuffer=self.encodeBuffer+data
- else:
- return self.coder.encode(data)
+ def receivedDecoded(self):
+ # If we're in streaming mode, encode and write the incoming data
+ if self.state==STREAM:
+ data=self.decodedSocket.readAll()
+ if data:
+ self.encodedSocket.write(self.coder.encode(data))
+ # Else do nothing, data will buffer until we've done the handshake
- def decode(self, data):
+ def receivedEncoded(self, data):
if self.state==HANDSHAKE:
- epub=self.read(data, HANDSHAKE_SIZE)
- if epub:
- esession=makeEphemeralSession(self.ekeypair, epub)
+ self.epub=self.read(self.encodedSocket, self.epub, HANDSHAKE_SIZE)
+ if self.checkTransition(self.epub, HANDSHAKE_SIZE, STREAM):
+ esession=makeEphemeralSession(self.ekeypair, self.epub)
self.coder=lite_socket(esession)
- self.state=STREAM
- self.server.write(self.encode(self.encodeBuffer))
- return decode(self.decodeBuffer)
- else:
- return None
+
+ data=self.decodedSocket.readAll()
+ if data:
+ self.encodedSocket.write(self.coder.encode(data))
+
+ data=self.encodedSocket.readAll()
+ if data:
+ self.decodedSocket.write(self.coder.decode(data))
else:
- return self.coder.decode(data)
+ data=self.encodedSocket.readAll()
+ if data:
+ self.decodedSocket.write(self.coder.decode(data))
def end(self):
pass
class DustClient(DustDaemon):
-
- def start(self):
- self.server.write(self.ekeypair.public.bytes)
+ pass
class DustServer(DustDaemon):
-
- def start(self):
- self.client.write(ekeypair.public.bytes)
+ pass
diff --git a/src/obfsproxy/transports/obfs2.py b/src/obfsproxy/transports/obfs2.py
new file mode 100644
index 0000000..25307be
--- /dev/null
+++ b/src/obfsproxy/transports/obfs2.py
@@ -0,0 +1,172 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+import os
+
+import random
+import hmac
+import hashlib
+import base64
+
+from obfsproxy.crypto.aes import AESCoder
+from obfsproxy.util import decode, uncompact
+
+MAGIC_VALUE = decode('2BF5CA7E')
+SEED_LENGTH = 16
+MAX_PADDING = 8192
+HASH_ITERATIONS = 100000
+
+KEYLEN = 16 # is the length of the key used by E(K,s) -- that is, 16.
+IVLEN = 16 # is the length of the IV used by E(K,s) -- that is, 16.
+
+HASHLEN = 16 # is the length of the output of H() -- that is, 32.
+
+READ_SEED=0
+READ_PADKEY=1
+READ_PADLEN=2
+READ_PADDING=3
+STREAM=4
+
+# H(x) is SHA256 of x.
+def h(x):
+ hasher = hashlib.sha256()
+ hasher.update(x)
+ return hasher.digest()
+
+# H^n(x) is H(x) called iteratively n times.
+def hn(x, n):
+ data=x
+ for x in range(n):
+ data=h(data)
+ return data
+
+# E(k,s) is the AES-CTR-128 encryption of s using K as key.
+def e(k, s):
+ cipher=AESCoder(k)
+ return cipher.encode(s)
+
+# D(k, s) is the AES-CTR-128 decryption of s using K as key.
+def d(k, s):
+ cipher=AESCoder(k)
+ return cipher.decode(s)
+
+# UINT32(n) is the 4 byte value of n in big-endian (network) order.
+def uint32(n):
+ return struct.pack('!I', (n))
+
+def decodeUint32(bs):
+ return struct.unpack('!I', bs)[0]
+
+# SR(n) is n bytes of strong random data.
+def sr(n):
+ return os.urandom(n)
+
+# WR(n) is n bytes of weaker random data.
+def wr(n):
+ return ''.join(chr(random.randint(0,255)) for _ in range(n))
+
+# MAC(s, x) = H(s | x | s)
+def mac(s, x):
+ return h(s+x+s)
+
+class Obfs2Daemon(BaseDaemon):
+
+ def __init__(self, decodedSocket, encodedSocket):
+ self.decodedSocket=decodedSocket
+ self.encodedSocket=encodedSocket
+ self.otherSeed=bytes('')
+ self.otherPadKeyEncrypted=bytes('')
+ self.otherPadLenBytes=bytes('')
+
+ def start(self):
+ # The initiator generates:
+ # INIT_SEED = SR(SEED_LENGTH)
+
+ self.seed=sr(SEED_LENGTH)
+ self.padKey=self.derivePadKey(self.seed, self.padString)
+
+ # Each then generates a random number PADLEN in range from 0 through MAX_PADDING (inclusive).
+ self.padLen=random.nextInt(MAX_PADDING) % MAX_PADDING
+
+ # The initiator then sends:
+ # INIT_SEED | E(INIT_PAD_KEY, UINT32(MAGIC_VALUE) | UINT32(PADLEN) | WR(PADLEN))
+ self.server.write(self.seed+e(self.padKey, uint32(MAGIC_VALUE))+uint32(self.padLen)+wr(self.padLen))
+
+ self.state=READ_SEED
+
+ def receivedDecoded(self):
+ if state==STREAM:
+ data=self.decodedSocket.readAll()
+ encodedData=encode(data)
+ self.encodedSocket.write(encodedData)
+
+ def receivedEncoded(self):
+ if state==READ_SEED:
+ self.otherSeed=self.read(self.encodedSocket, self.otherSeed, SEED_LENGTH)
+ if self.checkTransition(self.otherSeed, SEED_LENGTH, READ_PADKEY):
+ self.otherPadKeyDerived=self.derivePadKey(self.otherSeed, not self.server)
+ elif state==READ_PADKEY:
+ self.otherPadKeyEncrypted=self.read(self.encodedSocket, self.otherPadKeyEncrypted, KEYLEN)
+ if self.checkTransition(self.otherPadKeyEncrypted, KEYLEN, READ_PADLEN):
+ if self.otherPadKeyEncrypted!=self.otherPadKeyDerived:
+ self.encodedSocket.disconnect()
+ self.decodedSocket.disconnect()
+ elif state==READ_PADLEN:
+ self.otherPadLenBytes=self.read(self.encodedSocket, self.otherPadLenBytes, 4)
+ if self.checkTransition(self.otherPadLenBytes, 4, READ_PADDING):
+ self.otherPadLen=decodeUint32(self.otherPadLenBytes)
+ if self.otherPadLen>MAX_PADDING:
+ self.encodedSocket.disconnect()
+ self.decodedSocket.disconnect()
+ elif state==READ_PADDING:
+ self.otherPadding=self.read(self.encodedSocket, self.otherPadding, self.otherPadLen)
+ if self.checkTransition(self.otherPadding, self.otherPadLen, READ_PADDING):
+ self.secret=self.deriveSecret(self.seed, self.otherSeed, self.server)
+ self.otherSecret=self.deriveSecret(self.otherSeed, self.seed, not self.server)
+ # INIT_KEY = INIT_SECRET[:KEYLEN]
+ # RESP_KEY = RESP_SECRET[:KEYLEN]
+ self.key=self.secret[:KEYLEN]
+ self.otherKey=self.otherSecret[:KEYLEN]
+
+ # INIT_IV = INIT_SECRET[KEYLEN:]
+ # RESP_IV = RESP_SECRET[KEYLEN:]
+ self.iv=self.secret[KEYLEN:]
+ self.otheriv=self.otherSecret[KEYLEN:]
+
+ self.cipher=initCipher(self.iv, self.key)
+ self.otherCipher=initCipher(self.otheriv, self.otherKey)
+ elif state==STREAM:
+ data=self.encodedSocket.readAll()
+ decodedData=decode(data)
+ self.decodedSocket.write(decodedData)
+
+ def derivePadKey(self, seed, padString):
+ return mac(padString, seed)[:KEYLEN]
+
+ def deriveSecret(self, seed, otherSeed, server):
+ if server:
+ # RESP_SECRET = MAC("Responder obfuscated data", INIT_SEED|RESP_SEED)
+ return mac(self.padString, otherSeed+seed)
+ else:
+ # INIT_SECRET = MAC("Initiator obfuscated data", INIT_SEED|RESP_SEED)
+ return mac(self.padString, seed+otherSeed)
+
+ def initCipher(self, iv, key):
+ coder=AESCoder(key)
+ coder.encode(iv)
+ return coder
+
+ def end(self):
+ pass
+
+class Obfs2Client(Obfs3Daemon):
+
+ def __init__(self, decodedSocket, encodedSocket):
+ self.padString='Initiator obfuscation padding'
+ self.otherPadString='Responder obfuscation padding'
+
+class Obfs2Server(Obfs3Daemon):
+
+ def __init__(self, decodedSocket, encodedSocket):
+ self.padString='Responder obfuscation padding'
+ self.otherPadString='Initiator obfuscation padding'
diff --git a/src/obfsproxy/transports/obfs3.py b/src/obfsproxy/transports/obfs3.py
index 0b314e0..c4b4643 100644
--- a/src/obfsproxy/transports/obfs3.py
+++ b/src/obfsproxy/transports/obfs3.py
@@ -11,55 +11,50 @@ STREAM=1
HANDSHAKE_SIZE=IV_SIZE+KEY_SIZE
-class Obfs3Daemon:
+class Obfs3Daemon(BaseDaemon):
+
+ def __init__(self, decodedSocket, encodedSocket):
+ BaseDaemon.__init__(self, decodedSocket, encodedSocket)
- def __init__(self, client, server):
- self.client=client
- self.server=server
self.state=HANDSHAKE_WRITE
- self.encodeBuffer=bytes('')
- self.decodeBuffer=bytes('')
self.ekeypair=createEphemeralKeypair()
+ self.epub=bytes('')
- def read(self, data, count):
- if data:
- self.decodeBuffer=self.decodeBuffer+data
- if len(self.decodeBuffer)>=count:
- data=self.decodeBuffer[:count]
- self.decodeBuffer=self.decodeBuffer[count:]
- return data
- else:
- return None
+ def start(self):
+ self.encodedSocket.write(self.ekeypair.public.bytes)
- def encode(self, data):
- if self.state==HANDSHAKE:
- self.encodeBuffer=self.encodeBuffer+data
- else:
- return self.coder.encode(data)
+ def receivedDecoded(self):
+ # If we're in streaming mode, encode and write the incoming data
+ if self.state==STREAM:
+ data=self.decodedSocket.readAll()
+ if data:
+ self.encodedSocket.write(self.coder.encode(data))
+ # Else do nothing, data will buffer until we've done the handshake
- def decode(self, data):
+ def receivedEncoded(self, data):
if self.state==HANDSHAKE:
- epub=self.read(data, HANDSHAKE_SIZE)
- if epub:
- esession=makeEphemeralSession(self.ekeypair, epub)
+ self.epub=self.read(self.encodedSocket, self.epub, HANDSHAKE_SIZE)
+ if self.checkTransition(self.epub, HANDSHAKE_SIZE, STREAM):
+ esession=makeEphemeralSession(self.ekeypair, self.epub)
self.coder=AESCoder(esession)
- self.state=STREAM
- self.server.write(self.encode(self.encodeBuffer))
- return decode(self.decodeBuffer)
- else:
- return None
+
+ data=self.decodedSocket.readAll()
+ if data:
+ self.encodedSocket.write(self.coder.encode(data))
+
+ data=self.encodedSocket.readAll()
+ if data:
+ self.decodedSocket.write(self.coder.decode(data))
else:
- return self.coder.decode(data)
+ data=self.encodedSocket.readAll()
+ if data:
+ self.decodedSocket.write(self.coder.decode(data))
def end(self):
pass
class Obfs3Client(Obfs3Daemon):
-
- def start(self):
- self.server.write(self.ekeypair.public.bytes)
+ pass
class Obfs3Server(Obfs3Daemon):
-
- def start(self):
- self.client.write(ekeypair.public.bytes)
+ pass
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-privacy/packages/obfsproxy.git
More information about the Pkg-privacy-commits
mailing list