Browse Source

add auth_sha1

dev
BreakWa11 9 years ago
parent
commit
96495e7dd9
  1. 2
      config.json
  2. 210
      shadowsocks/obfsplugin/auth.py

2
config.json

@ -7,7 +7,7 @@
"password": "m", "password": "m",
"timeout": 120, "timeout": 120,
"method": "aes-256-cfb", "method": "aes-256-cfb",
"protocol": "origin", "protocol": "auth_sha1_compatible",
"obfs": "http_simple_compatible", "obfs": "http_simple_compatible",
"obfs_param": "", "obfs_param": "",
"dns_ipv6": false, "dns_ipv6": false,

210
shadowsocks/obfsplugin/auth.py

@ -36,11 +36,16 @@ from shadowsocks import common
from shadowsocks.obfsplugin import plain from shadowsocks.obfsplugin import plain
from shadowsocks.common import to_bytes, to_str, ord, chr from shadowsocks.common import to_bytes, to_str, ord, chr
def create_auth_obfs(method): def create_auth_simple(method):
return auth_simple(method) return auth_simple(method)
def create_auth_sha1(method):
return auth_sha1(method)
obfs_map = { obfs_map = {
'auth_simple': (create_auth_obfs,), 'auth_simple': (create_auth_simple,),
'auth_sha1': (create_auth_sha1,),
'auth_sha1_compatible': (create_auth_sha1,),
} }
def match_begin(str1, str2): def match_begin(str1, str2):
@ -192,7 +197,8 @@ class auth_simple(verify_base):
try: try:
max_client = int(server_info.protocol_param) max_client = int(server_info.protocol_param)
except: except:
pass max_client = 16
self.server_info.data.set_max_client(max_client)
def pack_data(self, buf): def pack_data(self, buf):
if len(buf) == 0: if len(buf) == 0:
@ -334,3 +340,201 @@ class auth_simple(verify_base):
self.decrypt_packet_num += 1 self.decrypt_packet_num += 1
return out_buf return out_buf
class auth_sha1(verify_base):
def __init__(self, method):
super(auth_sha1, self).__init__(method)
self.recv_buf = b''
self.unit_len = 8100
self.decrypt_packet_num = 0
self.raw_trans = False
self.has_sent_header = False
self.has_recv_header = False
self.client_id = 0
self.connection_id = 0
self.max_time_dif = 60 * 60 # time dif (second) setting
def init_data(self):
return obfs_auth_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 pack_data(self, buf):
if len(buf) == 0:
return b''
rnd_data = os.urandom(common.ord(os.urandom(1)[0]) % 16)
data = common.chr(len(rnd_data) + 1) + rnd_data + buf
data = struct.pack('>H', len(data) + 6) + data
adler32 = zlib.adler32(data) & 0xFFFFFFFF
data += struct.pack('<I', adler32)
return data
def pack_auth_data(self, buf):
if len(buf) == 0:
return b''
rnd_data = os.urandom(common.ord(os.urandom(1)[0]) % 128)
data = common.chr(len(rnd_data) + 1) + rnd_data + buf
data = struct.pack('>H', len(data) + 10) + data
crc = binascii.crc32(self.server_info.key)
data = struct.pack('<I', crc) + data
data += hmac.new(self.server_info.iv + self.server_info.key, data, hashlib.sha1).digest()[:10]
return data
def auth_data(self):
utc_time = int(time.time()) & 0xFFFFFFFF
if self.server_info.data.connection_id > 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('<I', os.urandom(4))[0] & 0xFFFFFF
self.server_info.data.connection_id += 1
return b''.join([struct.pack('<I', utc_time),
self.server_info.data.local_client_id,
struct.pack('<I', self.server_info.data.connection_id)])
def client_pre_encrypt(self, buf):
ret = b''
if not self.has_sent_header:
head_size = self.get_head_size(buf, 30)
datalen = min(len(buf), random.randint(0, 31) + head_size)
ret += self.pack_auth_data(self.auth_data() + buf[:datalen])
buf = buf[datalen:]
self.has_sent_header = True
while len(buf) > 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) > 2:
length = struct.unpack('>H', self.recv_buf[:2])[0]
if length >= 8192 or length < 7:
self.raw_trans = True
self.recv_buf = b''
if self.decrypt_packet_num == 0:
return None
else:
raise Exception('server_post_decrype data error')
if length > len(self.recv_buf):
break
if zlib.adler32(self.recv_buf[:length - 4]) != struct.unpack('<I', self.recv_buf[length - 4:length])[0]:
self.raw_trans = True
self.recv_buf = b''
if self.decrypt_packet_num == 0:
return None
else:
raise Exception('server_post_decrype data uncorrect checksum')
pos = common.ord(self.recv_buf[2]) + 2
out_buf += self.recv_buf[pos:length - 4]
self.recv_buf = self.recv_buf[length:]
if out_buf:
self.decrypt_packet_num += 1
return out_buf
def server_pre_encrypt(self, buf):
if self.raw_trans:
return buf
ret = b''
while len(buf) > 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
self.recv_buf += buf
out_buf = b''
if not self.has_recv_header:
if len(self.recv_buf) < 4:
return b''
crc = struct.pack('<I', binascii.crc32(self.server_info.key) & 0xFFFFFFFF)
if crc != self.recv_buf[:4]:
if self.method == 'auth_sha1':
return b'E'
else:
self.raw_trans = True
return self.recv_buf
length = struct.unpack('>H', self.recv_buf[4:6])[0]
if length > len(self.recv_buf):
return b''
sha1data = hmac.new(self.server_info.recv_iv + self.server_info.key, self.recv_buf[:length - 10], hashlib.sha1).digest()[:10]
if sha1data != self.recv_buf[length - 10:length]:
logging.error('server_post_decrype data uncorrect auth HMAC-SHA1')
return b'E'
pos = common.ord(self.recv_buf[6]) + 6
out_buf = self.recv_buf[pos:length - 10]
if len(out_buf) < 12:
self.raw_trans = True
self.recv_buf = b''
logging.info('auth_sha1: too short')
return b'E'
utc_time = struct.unpack('<I', out_buf[:4])[0]
client_id = struct.unpack('<I', out_buf[4:8])[0]
connection_id = struct.unpack('<I', out_buf[8:12])[0]
time_dif = common.int32((int(time.time()) & 0xffffffff) - utc_time)
if time_dif < -self.max_time_dif or time_dif > self.max_time_dif \
or common.int32(utc_time - self.server_info.data.startup_time) < -self.max_time_dif / 2:
self.raw_trans = True
self.recv_buf = b''
logging.info('auth_sha1: wrong timestamp, time_dif %d, data %s' % (time_dif, binascii.hexlify(out_buf),))
return b'E'
elif self.server_info.data.insert(client_id, connection_id):
self.has_recv_header = True
out_buf = out_buf[12:]
self.client_id = client_id
self.connection_id = connection_id
else:
self.raw_trans = True
self.recv_buf = b''
logging.info('auth_sha1: auth fail, data %s' % (binascii.hexlify(out_buf),))
return b'E'
self.recv_buf = self.recv_buf[length:]
self.has_recv_header = True
while len(self.recv_buf) > 2:
length = struct.unpack('>H', self.recv_buf[:2])[0]
if length >= 8192 or length < 7:
self.raw_trans = True
self.recv_buf = b''
if self.decrypt_packet_num == 0:
logging.info('auth_sha1: over size')
return b'E'
else:
raise Exception('server_post_decrype data error')
if length > len(self.recv_buf):
break
if zlib.adler32(self.recv_buf[:length - 4]) & 0xFFFFFFFF != struct.unpack('<I', self.recv_buf[length - 4:length])[0]:
logging.info('auth_sha1: checksum error, data %s' % (binascii.hexlify(self.recv_buf[:length]),))
self.raw_trans = True
self.recv_buf = b''
if self.decrypt_packet_num == 0:
return b'E'
else:
raise Exception('server_post_decrype data uncorrect checksum')
pos = common.ord(self.recv_buf[2]) + 2
out_buf += self.recv_buf[pos:length - 4]
self.recv_buf = self.recv_buf[length:]
if out_buf:
self.server_info.data.update(self.client_id, self.connection_id)
self.decrypt_packet_num += 1
return out_buf

Loading…
Cancel
Save