From 574a10a74320b20adb1190df1c8bce253c085cba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A0=B4=E5=A8=83=E9=85=B1?= Date: Sat, 1 Oct 2016 21:10:27 +0800 Subject: [PATCH] fix bugs in auth_aes128 when run as a client add auth_aes128_sha1 --- shadowsocks/obfsplugin/auth.py | 293 +++++++++++++++++++++++++++++++-- 1 file changed, 282 insertions(+), 11 deletions(-) diff --git a/shadowsocks/obfsplugin/auth.py b/shadowsocks/obfsplugin/auth.py index bb7c238..bf5c2c7 100644 --- a/shadowsocks/obfsplugin/auth.py +++ b/shadowsocks/obfsplugin/auth.py @@ -51,6 +51,9 @@ def create_auth_sha1_v4(method): def create_auth_aes128(method): return auth_aes128(method) +def create_auth_aes128_sha1(method): + return auth_aes128_sha1(method) + obfs_map = { 'auth_sha1': (create_auth_sha1,), 'auth_sha1_compatible': (create_auth_sha1,), @@ -61,6 +64,8 @@ obfs_map = { 'auth_sha1_v4': (create_auth_sha1_v4,), 'auth_sha1_v4_compatible': (create_auth_sha1_v4,), 'auth_aes128': (create_auth_aes128,), + 'auth_aes128_sha1': (create_auth_aes128_sha1,), + 'auth_aes128_sha1_compatible': (create_auth_aes128_sha1,), } def match_begin(str1, str2): @@ -73,9 +78,9 @@ class obfs_verify_data(object): def __init__(self): pass -class verify_base(plain.plain): +class auth_base(plain.plain): def __init__(self, method): - super(verify_base, self).__init__(method) + super(auth_base, self).__init__(method) self.method = method self.no_compatible_method = '' @@ -198,7 +203,7 @@ class obfs_auth_data(object): else: return self.client_id[client_id].insert(connection_id) -class auth_sha1(verify_base): +class auth_sha1(auth_base): def __init__(self, method): super(auth_sha1, self).__init__(method) self.recv_buf = b'' @@ -420,7 +425,7 @@ class obfs_auth_v2_data(object): else: return self.client_id[client_id].insert(connection_id) -class auth_sha1_v2(verify_base): +class auth_sha1_v2(auth_base): def __init__(self, method): super(auth_sha1_v2, self).__init__(method) self.recv_buf = b'' @@ -621,7 +626,7 @@ class auth_sha1_v2(verify_base): self.decrypt_packet_num += 1 return (out_buf, sendback) -class auth_sha1_v3(verify_base): +class auth_sha1_v3(auth_base): def __init__(self, method): super(auth_sha1_v3, self).__init__(method) self.recv_buf = b'' @@ -830,7 +835,7 @@ class auth_sha1_v3(verify_base): self.decrypt_packet_num += 1 return (out_buf, sendback) -class auth_sha1_v4(verify_base): +class auth_sha1_v4(auth_base): def __init__(self, method): super(auth_sha1_v4, self).__init__(method) self.recv_buf = b'' @@ -1056,7 +1061,7 @@ class auth_sha1_v4(verify_base): self.decrypt_packet_num += 1 return (out_buf, sendback) -class auth_aes128(verify_base): +class auth_aes128(auth_base): def __init__(self, method): super(auth_aes128, self).__init__(method) self.recv_buf = b'' @@ -1119,15 +1124,14 @@ class auth_aes128(verify_base): else: rnd_len = struct.unpack('H', os.urandom(2))[0] % 1024 + self.pack_id = 0 + self.recv_id = 0 + + def init_data(self): + return obfs_auth_v2_data() + + def set_server_info(self, server_info): + self.server_info = server_info + try: + max_client = int(server_info.protocol_param) + except: + max_client = 64 + self.server_info.data.set_max_client(max_client) + + def rnd_data(self, buf_size): + if buf_size > 1200: + return b'\x01' + + if self.pack_id > 4: + rnd_data = os.urandom(common.ord(os.urandom(1)[0]) % 32) + elif buf_size > 400: + rnd_data = os.urandom(common.ord(os.urandom(1)[0]) % 128) + else: + rnd_data = os.urandom(struct.unpack('>H', os.urandom(2))[0] % 512) + + if len(rnd_data) < 128: + return common.chr(len(rnd_data) + 1) + rnd_data + else: + return common.chr(255) + struct.pack(' 400: + rnd_len = struct.unpack(' 0xFF000000: + self.server_info.data.local_client_id = b'' + if not self.server_info.data.local_client_id: + self.server_info.data.local_client_id = os.urandom(4) + logging.debug("local_client_id %s" % (binascii.hexlify(self.server_info.data.local_client_id),)) + self.server_info.data.connection_id = struct.unpack(' self.unit_len: + ret += self.pack_data(buf[:self.unit_len]) + buf = buf[self.unit_len:] + ret += self.pack_data(buf) + return ret + + def client_post_decrypt(self, buf): + if self.raw_trans: + return buf + self.recv_buf += buf + out_buf = b'' + while len(self.recv_buf) > 4: + mac_key = self.server_info.key + struct.pack('= 8192 or length < 7: + self.raw_trans = True + self.recv_buf = b'' + raise Exception('client_post_decrypt data error') + if length > len(self.recv_buf): + break + + if hmac.new(mac_key, self.recv_buf[:length - 4], hashlib.sha1).digest()[:4] != self.recv_buf[length - 4:length]: + self.raw_trans = True + self.recv_buf = b'' + raise Exception('client_post_decrypt data uncorrect checksum') + + self.recv_id = (self.recv_id + 1) & 0xFFFFFFFF + pos = common.ord(self.recv_buf[4]) + if pos < 255: + pos += 4 + else: + pos = struct.unpack(' self.unit_len: + ret += self.pack_data(buf[:self.unit_len]) + buf = buf[self.unit_len:] + ret += self.pack_data(buf) + return ret + + def server_post_decrypt(self, buf): + if self.raw_trans: + return (buf, False) + self.recv_buf += buf + out_buf = b'' + sendback = False + + if not self.has_recv_header: + if len(self.recv_buf) < 7: + return (b'', False) + mac_key = self.server_info.recv_iv + self.server_info.key + sha1data = hmac.new(mac_key, self.recv_buf[:3], hashlib.sha1).digest()[:4] + if sha1data != self.recv_buf[3:7]: + return self.not_match_return(self.recv_buf) + + if len(self.recv_buf) < 31: + return (b'', False) + sha1data = hmac.new(mac_key, self.recv_buf[7:27], hashlib.sha1).digest()[:4] + if sha1data != self.recv_buf[27:31]: + logging.error('auth_aes128_sha1 data uncorrect auth HMAC-SHA1 from %s:%d, data %s' % (self.server_info.client, self.server_info.client_port, binascii.hexlify(self.recv_buf))) + if len(self.recv_buf) < 31 + self.extra_wait_size: + return (b'', False) + return self.not_match_return(self.recv_buf) + + user_key = self.recv_buf[7:11] + encryptor = encrypt.Encryptor(to_bytes(base64.b64encode(user_key + self.server_info.key)) + self.salt, 'aes-128-cbc') + head = encryptor.decrypt(b'\x00' * 16 + self.recv_buf[11:27] + b'\x00') # need an extra byte or recv empty + length = struct.unpack(' self.max_time_dif: + logging.info('auth_aes128_sha1: wrong timestamp, time_dif %d, data %s' % (time_dif, binascii.hexlify(head),)) + return self.not_match_return(self.recv_buf) + elif self.server_info.data.insert(client_id, connection_id): + self.has_recv_header = True + out_buf = self.recv_buf[31 + rnd_len:length - 4] + self.client_id = client_id + self.connection_id = connection_id + else: + logging.info('auth_aes128_sha1: auth fail, data %s' % (binascii.hexlify(out_buf),)) + return self.not_match_return(self.recv_buf) + self.recv_buf = self.recv_buf[length:] + self.has_recv_header = True + sendback = True + + while len(self.recv_buf) > 4: + mac_key = self.server_info.key + struct.pack('= 8192 or length < 7: + self.raw_trans = True + self.recv_buf = b'' + if self.recv_id == 0: + logging.info('auth_aes128_sha1: over size') + return (b'E', False) + else: + raise Exception('server_post_decrype data error') + if length > len(self.recv_buf): + break + + if hmac.new(mac_key, self.recv_buf[:length - 4], hashlib.sha1).digest()[:4] != self.recv_buf[length - 4:length]: + logging.info('auth_aes128_sha1: checksum error, data %s' % (binascii.hexlify(self.recv_buf[:length]),)) + self.raw_trans = True + self.recv_buf = b'' + if self.recv_id == 0: + return (b'E', False) + else: + raise Exception('server_post_decrype data uncorrect checksum') + + self.recv_id = (self.recv_id + 1) & 0xFFFFFFFF + pos = common.ord(self.recv_buf[4]) + if pos < 255: + pos += 4 + else: + pos = struct.unpack('