commit 7b562f53fb02f930b3c43f1571a90f6634df0664
Author: George Kadianakis <desnacked(a)riseup.net>
Date: Sat Apr 26 19:14:51 2014 +0100
Make sure that AES-CTR counter of obfs{2,3} won't overflow.
---
ChangeLog | 4 ++++
obfsproxy/common/aes.py | 11 ++++++++---
obfsproxy/transports/obfs2.py | 6 ++++--
obfsproxy/transports/obfs3.py | 3 ++-
4 files changed, 18 insertions(+), 6 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 6cf2400..8c2e76c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -7,6 +7,10 @@ Changes in version 0.2.9 - UNRELEASED:
explicitly picks python2. Makes obfsproxy work in platforms like
Linux Arch where python3 is the default. Fixes part of #11190.
Patch by Yawning Angel.
+ - The AES-CTR counter of obfs2 and obfs3 now wraps around to 0.
+ Since, the counter value was derived from the protocol, there
+ was an unlikely chance that PyCrypto would raise an OverflowError
+ exception. Spotted by Yawning Angel. Fixes #11611.
Changes in version 0.2.8 - 2014-03-28:
diff --git a/obfsproxy/common/aes.py b/obfsproxy/common/aes.py
index 3f29346..777fad0 100644
--- a/obfsproxy/common/aes.py
+++ b/obfsproxy/common/aes.py
@@ -9,13 +9,18 @@ from Crypto.Util import Counter
class AES_CTR_128(object):
"""An AES-CTR-128 PyCrypto wrapper."""
- def __init__(self, key, iv):
- """Initialize AES with the given key and IV."""
+ def __init__(self, key, iv, counter_wraparound=False):
+ """Initialize AES with the given key and IV.
+
+ If counter_wraparound is set to True, the AES-CTR counter will
+ wraparound to 0 when it overflows.
+ """
assert(len(key) == 16)
assert(len(iv) == 16)
- self.ctr = Counter.new(128, initial_value=long(iv.encode('hex'), 16))
+ self.ctr = Counter.new(128, initial_value=long(iv.encode('hex'), 16),
+ allow_wraparound=counter_wraparound)
self.cipher = AES.new(key, AES.MODE_CTR, counter=self.ctr)
def crypt(self, data):
diff --git a/obfsproxy/transports/obfs2.py b/obfsproxy/transports/obfs2.py
index f8ba7c9..23a60d4 100644
--- a/obfsproxy/transports/obfs2.py
+++ b/obfsproxy/transports/obfs2.py
@@ -257,7 +257,8 @@ class Obfs2Transport(base.BaseTransport):
secret = self.mac(pad_string,
self.initiator_seed + self.responder_seed,
self.shared_secret)
- return aes.AES_CTR_128(secret[:KEYLEN], secret[KEYLEN:])
+ return aes.AES_CTR_128(secret[:KEYLEN], secret[KEYLEN:],
+ counter_wraparound=True)
def _derive_padding_crypto(self, seed, pad_string): # XXX consider secret_seed
"""
@@ -266,7 +267,8 @@ class Obfs2Transport(base.BaseTransport):
secret = self.mac(pad_string,
seed,
self.shared_secret)
- return aes.AES_CTR_128(secret[:KEYLEN], secret[KEYLEN:])
+ return aes.AES_CTR_128(secret[:KEYLEN], secret[KEYLEN:],
+ counter_wraparound=True)
def mac(self, s, x, secret):
"""
diff --git a/obfsproxy/transports/obfs3.py b/obfsproxy/transports/obfs3.py
index 6a4df6b..ba45da1 100644
--- a/obfsproxy/transports/obfs3.py
+++ b/obfsproxy/transports/obfs3.py
@@ -221,7 +221,8 @@ class Obfs3Transport(base.BaseTransport):
Derive and return an obfs3 key using the pad string in 'pad_string'.
"""
secret = hmac_sha256.hmac_sha256_digest(self.shared_secret, pad_string)
- return aes.AES_CTR_128(secret[:KEYLEN], secret[KEYLEN:])
+ return aes.AES_CTR_128(secret[:KEYLEN], secret[KEYLEN:],
+ counter_wraparound=True)
class Obfs3Client(Obfs3Transport):