From 5bde27ca50070115aab237cdf1f9eb1205a6c0f4 Mon Sep 17 00:00:00 2001 From: Akkariiin Date: Mon, 21 Aug 2017 19:35:08 +0800 Subject: [PATCH 01/14] auth_chain_f ? --- shadowsocks/obfsplugin/auth_chain.py | 51 ++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/shadowsocks/obfsplugin/auth_chain.py b/shadowsocks/obfsplugin/auth_chain.py index d9d3326..b40d699 100644 --- a/shadowsocks/obfsplugin/auth_chain.py +++ b/shadowsocks/obfsplugin/auth_chain.py @@ -60,12 +60,17 @@ def create_auth_chain_e(method): return auth_chain_e(method) +def create_auth_chain_f(method): + return auth_chain_f(method) + + obfs_map = { 'auth_chain_a': (create_auth_chain_a,), 'auth_chain_b': (create_auth_chain_b,), 'auth_chain_c': (create_auth_chain_c,), 'auth_chain_d': (create_auth_chain_d,), 'auth_chain_e': (create_auth_chain_e,), + 'auth_chain_f': (create_auth_chain_f,), } @@ -858,3 +863,49 @@ class auth_chain_e(auth_chain_d): # use the mini size in the data_size_list0 pos = bisect.bisect_left(self.data_size_list0, other_data_size) return self.data_size_list0[pos] - other_data_size + + +# auth_chain_f +# when every connect create, generate size_list will different when every day or every custom time interval witch set in the config +class auth_chain_f(auth_chain_e): + def __init__(self, method): + super(auth_chain_e, self).__init__(method) + self.salt = b"auth_chain_f" + self.no_compatible_method = 'auth_chain_f' + + def set_server_info(self, server_info): + self.server_info = server_info + try: + max_client = int(server_info.protocol_param.split('#')[0]) + except: + max_client = 64 + try: + self.key_change_interval = int(server_info.protocol_param.split('#')[1]) # config are in second + except: + self.key_change_interval = 60 * 60 * 24 # a day + self.key_change_datetime_key = int(int(time.time()) / self.key_change_interval) + self.key_change_datetime_key_bytes = [] + for i in range(7, -1, -1): # big-ending compare to c + self.key_change_datetime_key_bytes.append((self.key_change_datetime_key >> (8 * i)) & 0xFF) + self.server_info.data.set_max_client(max_client) + self.init_data_size(self.server_info.key) + + def init_data_size(self, key): + if self.data_size_list0: + self.data_size_list0 = [] + random = xorshift128plus() + # key xor with key_change_datetime_key + new_key = [] + for i in range(0, 8): + new_key.append(key[i] ^ self.key_change_datetime_key_bytes[i]) + random.init_from_bin(new_key) + # 补全数组长为12~24-1 + list_len = random.next() % (8 + 16) + (4 + 8) + for i in range(0, list_len): + self.data_size_list0.append((int)(random.next() % 2340 % 2040 % 1440)) + self.data_size_list0.sort() + old_len = len(self.data_size_list0) + self.check_and_patch_data_size(random) + # if check_and_patch_data_size are work, re-sort again. + if old_len != len(self.data_size_list0): + self.data_size_list0.sort() From ef3e45573951f67423735cec88466e7a59ad6fcc Mon Sep 17 00:00:00 2001 From: Akkariiin Date: Thu, 14 Sep 2017 16:10:08 +0800 Subject: [PATCH 02/14] add notes to find_library_nt function --- shadowsocks/crypto/util.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/shadowsocks/crypto/util.py b/shadowsocks/crypto/util.py index 212df86..679540d 100644 --- a/shadowsocks/crypto/util.py +++ b/shadowsocks/crypto/util.py @@ -22,6 +22,13 @@ import logging def find_library_nt(name): + # type: (str) -> list + """ + find lib in windows in all the directory in path env + + :param name: can end with `.dll` or not + :return: lib results list + """ # modified from ctypes.util # ctypes.util.find_library just returns first result he found # but we want to try them all From e540ea171bb3736b63a5a28f1bd82e5298c5439b Mon Sep 17 00:00:00 2001 From: Akkariiin Date: Thu, 14 Sep 2017 16:12:13 +0800 Subject: [PATCH 03/14] add aes-256-gcm to openssl test all the method make some format --- shadowsocks/crypto/openssl.py | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/shadowsocks/crypto/openssl.py b/shadowsocks/crypto/openssl.py index abefc33..3918bcc 100644 --- a/shadowsocks/crypto/openssl.py +++ b/shadowsocks/crypto/openssl.py @@ -17,7 +17,7 @@ from __future__ import absolute_import, division, print_function, \ with_statement -from ctypes import c_char_p, c_int, c_long, byref,\ +from ctypes import c_char_p, c_int, c_long, byref, \ create_string_buffer, c_void_p from shadowsocks import common @@ -77,6 +77,7 @@ def load_cipher(cipher_name): return cipher() return None + def rand_bytes(length): if not loaded: load_openssl() @@ -86,6 +87,7 @@ def rand_bytes(length): raise Exception('RAND_bytes return error') return buf.raw + class OpenSSLCrypto(object): def __init__(self, cipher_name, key, iv, op): self._ctx = None @@ -133,6 +135,9 @@ ciphers = { 'aes-128-cbc': (16, 16, OpenSSLCrypto), 'aes-192-cbc': (24, 16, OpenSSLCrypto), 'aes-256-cbc': (32, 16, OpenSSLCrypto), + 'aes-128-gcm': (16, 16, OpenSSLCrypto), + 'aes-192-gcm': (24, 16, OpenSSLCrypto), + 'aes-256-gcm': (32, 16, OpenSSLCrypto), 'aes-128-cfb': (16, 16, OpenSSLCrypto), 'aes-192-cfb': (24, 16, OpenSSLCrypto), 'aes-256-cfb': (32, 16, OpenSSLCrypto), @@ -162,7 +167,6 @@ ciphers = { def run_method(method): - cipher = OpenSSLCrypto(method, b'k' * 32, b'i' * 16, 1) decipher = OpenSSLCrypto(method, b'k' * 32, b'i' * 16, 0) @@ -197,5 +201,20 @@ def test_rc4(): run_method('rc4') +def test_all(): + for k, v in ciphers.items(): + print(k) + try: + run_method(k) + except AssertionError as e: + eprint("AssertionError===========" + k) + eprint(e) + + +def eprint(*args, **kwargs): + import sys + print(*args, file=sys.stderr, **kwargs) + + if __name__ == '__main__': - test_aes_128_cfb() + test_all() From 11f4b47939203cc83726c4d554ff445f65ce70ba Mon Sep 17 00:00:00 2001 From: Akkariiin Date: Fri, 15 Sep 2017 18:55:45 +0800 Subject: [PATCH 04/14] add a notice for CBC mode --- shadowsocks/crypto/openssl.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/shadowsocks/crypto/openssl.py b/shadowsocks/crypto/openssl.py index 3918bcc..e4980a4 100644 --- a/shadowsocks/crypto/openssl.py +++ b/shadowsocks/crypto/openssl.py @@ -132,6 +132,8 @@ class OpenSSLCrypto(object): ciphers = { + # CBC mode need a special use way that different from other. + # CBC mode encrypt message with 16n length, and need 16n+1 length space to decrypt it , otherwise don't decrypt it 'aes-128-cbc': (16, 16, OpenSSLCrypto), 'aes-192-cbc': (24, 16, OpenSSLCrypto), 'aes-256-cbc': (32, 16, OpenSSLCrypto), From 5d0e345b382df635361e6cd12a23804562ff22eb Mon Sep 17 00:00:00 2001 From: Akkariiin Date: Fri, 15 Sep 2017 19:04:33 +0800 Subject: [PATCH 05/14] add xchacha20 and xsalsa20 support xchacha20 only support since libsodium v1.0.12 --- shadowsocks/crypto/sodium.py | 55 ++++++++++++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/shadowsocks/crypto/sodium.py b/shadowsocks/crypto/sodium.py index 25705f7..a0273c5 100644 --- a/shadowsocks/crypto/sodium.py +++ b/shadowsocks/crypto/sodium.py @@ -20,6 +20,8 @@ from __future__ import absolute_import, division, print_function, \ from ctypes import c_char_p, c_int, c_ulong, c_ulonglong, byref, \ create_string_buffer, c_void_p +import sys + from shadowsocks.crypto import util __all__ = ['ciphers'] @@ -55,10 +57,31 @@ def load_libsodium(): try: libsodium.crypto_stream_chacha20_ietf_xor_ic.restype = c_int libsodium.crypto_stream_chacha20_ietf_xor_ic.argtypes = (c_void_p, c_char_p, - c_ulonglong, - c_char_p, c_ulong, - c_char_p) + c_ulonglong, + c_char_p, c_ulong, + c_char_p) + except: + print("ChaCha20 IETF not support.", file=sys.stderr) + pass + + try: + libsodium.crypto_stream_xsalsa20_xor_ic.restype = c_int + libsodium.crypto_stream_xsalsa20_xor_ic.argtypes = (c_void_p, c_char_p, + c_ulonglong, + c_char_p, c_ulonglong, + c_char_p) + except: + print("XSalsa20 not support.", file=sys.stderr) + pass + + try: + libsodium.crypto_stream_xchacha20_xor_ic.restype = c_int + libsodium.crypto_stream_xchacha20_xor_ic.argtypes = (c_void_p, c_char_p, + c_ulonglong, + c_char_p, c_ulonglong, + c_char_p) except: + print("XChaCha20 not support. XChaCha20 only support since libsodium v1.0.12", file=sys.stderr) pass buf = create_string_buffer(buf_size) @@ -79,6 +102,10 @@ class SodiumCrypto(object): self.cipher = libsodium.crypto_stream_chacha20_xor_ic elif cipher_name == 'chacha20-ietf': self.cipher = libsodium.crypto_stream_chacha20_ietf_xor_ic + elif cipher_name == 'xchacha20': + self.cipher = libsodium.crypto_stream_xchacha20_xor_ic + elif cipher_name == 'xsalsa20': + self.cipher = libsodium.crypto_stream_xsalsa20_xor_ic else: raise Exception('Unknown cipher') # byte counter, not block counter @@ -107,10 +134,13 @@ class SodiumCrypto(object): def clean(self): pass + ciphers = { 'salsa20': (32, 8, SodiumCrypto), 'chacha20': (32, 8, SodiumCrypto), 'chacha20-ietf': (32, 12, SodiumCrypto), + 'xchacha20': (32, 24, SodiumCrypto), + 'xsalsa20': (32, 24, SodiumCrypto), } @@ -122,7 +152,6 @@ def test_salsa20(): def test_chacha20(): - cipher = SodiumCrypto('chacha20', b'k' * 32, b'i' * 16, 1) decipher = SodiumCrypto('chacha20', b'k' * 32, b'i' * 16, 0) @@ -130,13 +159,29 @@ def test_chacha20(): def test_chacha20_ietf(): - cipher = SodiumCrypto('chacha20-ietf', b'k' * 32, b'i' * 16, 1) decipher = SodiumCrypto('chacha20-ietf', b'k' * 32, b'i' * 16, 0) util.run_cipher(cipher, decipher) + +def test_xchacha20(): + cipher = SodiumCrypto('xchacha20', b'k' * 32, b'i' * 24, 1) + decipher = SodiumCrypto('xchacha20', b'k' * 32, b'i' * 24, 0) + + util.run_cipher(cipher, decipher) + + +def test_xsalsa20(): + cipher = SodiumCrypto('xsalsa20', b'k' * 32, b'i' * 24, 1) + decipher = SodiumCrypto('xsalsa20', b'k' * 32, b'i' * 24, 0) + + util.run_cipher(cipher, decipher) + + if __name__ == '__main__': test_chacha20_ietf() test_chacha20() test_salsa20() + test_xchacha20() + test_xsalsa20() From 0b4001775ccd9b1b1dc410cd5fae2053f81cc690 Mon Sep 17 00:00:00 2001 From: Akkariiin Date: Mon, 18 Sep 2017 18:49:26 +0800 Subject: [PATCH 06/14] fix AuthChain_f --- shadowsocks/obfsplugin/auth_chain.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/shadowsocks/obfsplugin/auth_chain.py b/shadowsocks/obfsplugin/auth_chain.py index b40d699..ad494b4 100644 --- a/shadowsocks/obfsplugin/auth_chain.py +++ b/shadowsocks/obfsplugin/auth_chain.py @@ -866,7 +866,7 @@ class auth_chain_e(auth_chain_d): # auth_chain_f -# when every connect create, generate size_list will different when every day or every custom time interval witch set in the config +# when every connect create, generate size_list will different when every day or every custom time interval which set in the config class auth_chain_f(auth_chain_e): def __init__(self, method): super(auth_chain_e, self).__init__(method) @@ -884,7 +884,7 @@ class auth_chain_f(auth_chain_e): except: self.key_change_interval = 60 * 60 * 24 # a day self.key_change_datetime_key = int(int(time.time()) / self.key_change_interval) - self.key_change_datetime_key_bytes = [] + self.key_change_datetime_key_bytes = [] # big bit first list for i in range(7, -1, -1): # big-ending compare to c self.key_change_datetime_key_bytes.append((self.key_change_datetime_key >> (8 * i)) & 0xFF) self.server_info.data.set_max_client(max_client) @@ -895,9 +895,9 @@ class auth_chain_f(auth_chain_e): self.data_size_list0 = [] random = xorshift128plus() # key xor with key_change_datetime_key - new_key = [] + new_key = list(key) for i in range(0, 8): - new_key.append(key[i] ^ self.key_change_datetime_key_bytes[i]) + new_key[i] ^= self.key_change_datetime_key_bytes[i] random.init_from_bin(new_key) # 补全数组长为12~24-1 list_len = random.next() % (8 + 16) + (4 + 8) From ae6ba02163d40336909a01646627547c8508db10 Mon Sep 17 00:00:00 2001 From: Akkariiin Date: Mon, 18 Sep 2017 18:49:49 +0800 Subject: [PATCH 07/14] use logging to replace error print --- shadowsocks/crypto/sodium.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/shadowsocks/crypto/sodium.py b/shadowsocks/crypto/sodium.py index a0273c5..390941c 100644 --- a/shadowsocks/crypto/sodium.py +++ b/shadowsocks/crypto/sodium.py @@ -20,7 +20,7 @@ from __future__ import absolute_import, division, print_function, \ from ctypes import c_char_p, c_int, c_ulong, c_ulonglong, byref, \ create_string_buffer, c_void_p -import sys +import logging from shadowsocks.crypto import util @@ -61,7 +61,7 @@ def load_libsodium(): c_char_p, c_ulong, c_char_p) except: - print("ChaCha20 IETF not support.", file=sys.stderr) + logging.info("ChaCha20 IETF not support.") pass try: @@ -71,7 +71,7 @@ def load_libsodium(): c_char_p, c_ulonglong, c_char_p) except: - print("XSalsa20 not support.", file=sys.stderr) + logging.info("XSalsa20 not support.") pass try: @@ -81,7 +81,7 @@ def load_libsodium(): c_char_p, c_ulonglong, c_char_p) except: - print("XChaCha20 not support. XChaCha20 only support since libsodium v1.0.12", file=sys.stderr) + logging.info("XChaCha20 not support. XChaCha20 only support since libsodium v1.0.12") pass buf = create_string_buffer(buf_size) From 9b2de514f9d06bc39d0c647bf119626c9bfee954 Mon Sep 17 00:00:00 2001 From: Akkariiin Date: Sun, 24 Sep 2017 13:34:36 +0800 Subject: [PATCH 08/14] add comments --- shadowsocks/obfsplugin/auth_chain.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shadowsocks/obfsplugin/auth_chain.py b/shadowsocks/obfsplugin/auth_chain.py index ad494b4..1413819 100644 --- a/shadowsocks/obfsplugin/auth_chain.py +++ b/shadowsocks/obfsplugin/auth_chain.py @@ -882,7 +882,7 @@ class auth_chain_f(auth_chain_e): try: self.key_change_interval = int(server_info.protocol_param.split('#')[1]) # config are in second except: - self.key_change_interval = 60 * 60 * 24 # a day + self.key_change_interval = 60 * 60 * 24 # a day by second self.key_change_datetime_key = int(int(time.time()) / self.key_change_interval) self.key_change_datetime_key_bytes = [] # big bit first list for i in range(7, -1, -1): # big-ending compare to c From 5d8e0e8ddb5a6dc8e7525180d60d771b61be18aa Mon Sep 17 00:00:00 2001 From: Akkariiin Date: Sun, 24 Sep 2017 15:19:36 +0800 Subject: [PATCH 09/14] fix auth_chain_e --- shadowsocks/obfsplugin/auth_chain.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shadowsocks/obfsplugin/auth_chain.py b/shadowsocks/obfsplugin/auth_chain.py index 1413819..42abeea 100644 --- a/shadowsocks/obfsplugin/auth_chain.py +++ b/shadowsocks/obfsplugin/auth_chain.py @@ -850,7 +850,7 @@ class auth_chain_d(auth_chain_b): class auth_chain_e(auth_chain_d): def __init__(self, method): - super(auth_chain_d, self).__init__(method) + super(auth_chain_e, self).__init__(method) self.salt = b"auth_chain_e" self.no_compatible_method = 'auth_chain_e' @@ -869,7 +869,7 @@ class auth_chain_e(auth_chain_d): # when every connect create, generate size_list will different when every day or every custom time interval which set in the config class auth_chain_f(auth_chain_e): def __init__(self, method): - super(auth_chain_e, self).__init__(method) + super(auth_chain_f, self).__init__(method) self.salt = b"auth_chain_f" self.no_compatible_method = 'auth_chain_f' From 63012e7e326ccdf7c3284f93c062c57390d9d2fe Mon Sep 17 00:00:00 2001 From: Akkariiin Date: Sun, 24 Sep 2017 15:44:25 +0800 Subject: [PATCH 10/14] fix auth_chain_f --- shadowsocks/obfsplugin/auth_chain.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shadowsocks/obfsplugin/auth_chain.py b/shadowsocks/obfsplugin/auth_chain.py index 42abeea..05ca045 100644 --- a/shadowsocks/obfsplugin/auth_chain.py +++ b/shadowsocks/obfsplugin/auth_chain.py @@ -897,7 +897,7 @@ class auth_chain_f(auth_chain_e): # key xor with key_change_datetime_key new_key = list(key) for i in range(0, 8): - new_key[i] ^= self.key_change_datetime_key_bytes[i] + new_key[i] = ord(new_key[i]) ^ self.key_change_datetime_key_bytes[i] random.init_from_bin(new_key) # 补全数组长为12~24-1 list_len = random.next() % (8 + 16) + (4 + 8) From 12cba3092e4974fe4829a3b2f38804c19dc66e5b Mon Sep 17 00:00:00 2001 From: Akkariiin Date: Sun, 24 Sep 2017 15:46:24 +0800 Subject: [PATCH 11/14] fix auth_chain_f --- shadowsocks/obfsplugin/auth_chain.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shadowsocks/obfsplugin/auth_chain.py b/shadowsocks/obfsplugin/auth_chain.py index 05ca045..1134221 100644 --- a/shadowsocks/obfsplugin/auth_chain.py +++ b/shadowsocks/obfsplugin/auth_chain.py @@ -897,7 +897,7 @@ class auth_chain_f(auth_chain_e): # key xor with key_change_datetime_key new_key = list(key) for i in range(0, 8): - new_key[i] = ord(new_key[i]) ^ self.key_change_datetime_key_bytes[i] + new_key[i] = chr(ord(new_key[i]) ^ self.key_change_datetime_key_bytes[i]) random.init_from_bin(new_key) # 补全数组长为12~24-1 list_len = random.next() % (8 + 16) + (4 + 8) From dbd85077e7b3491cca70d4691b8d2f163b7c9137 Mon Sep 17 00:00:00 2001 From: AkaneAkaza Date: Mon, 25 Sep 2017 13:24:25 +0800 Subject: [PATCH 12/14] fix mu list --- shadowsocks/obfs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shadowsocks/obfs.py b/shadowsocks/obfs.py index 3dfdb14..499ca1b 100644 --- a/shadowsocks/obfs.py +++ b/shadowsocks/obfs.py @@ -35,7 +35,7 @@ method_supported.update(auth.obfs_map) method_supported.update(auth_chain.obfs_map) def mu_protocol(): - return ["auth_aes128_md5", "auth_aes128_sha1", "auth_chain_a"] + return ["auth_aes128_md5", "auth_aes128_sha1", "auth_chain_a", "auth_chain_b", "auth_chain_c", "auth_chain_d", "auth_chain_e"] class server_info(object): def __init__(self, data): From 9a5c7da37ac887d4d4a544f3a98bef56cccb71fa Mon Sep 17 00:00:00 2001 From: Akkariiin Date: Thu, 28 Sep 2017 11:57:06 +0800 Subject: [PATCH 13/14] fix anth_chain_f issue --- shadowsocks/obfsplugin/auth_chain.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shadowsocks/obfsplugin/auth_chain.py b/shadowsocks/obfsplugin/auth_chain.py index 1134221..66fce90 100644 --- a/shadowsocks/obfsplugin/auth_chain.py +++ b/shadowsocks/obfsplugin/auth_chain.py @@ -897,7 +897,7 @@ class auth_chain_f(auth_chain_e): # key xor with key_change_datetime_key new_key = list(key) for i in range(0, 8): - new_key[i] = chr(ord(new_key[i]) ^ self.key_change_datetime_key_bytes[i]) + new_key[i] = to_str(to_bytes(new_key[i]) ^ self.key_change_datetime_key_bytes[i]) random.init_from_bin(new_key) # 补全数组长为12~24-1 list_len = random.next() % (8 + 16) + (4 + 8) From f0ec72c4c4fae73a0f89b44825144fefe0b622f4 Mon Sep 17 00:00:00 2001 From: Akkariiin Date: Thu, 28 Sep 2017 14:24:04 +0800 Subject: [PATCH 14/14] fix anth_chain_f cannot use, anth_chain_f now can run --- shadowsocks/obfsplugin/auth_chain.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/shadowsocks/obfsplugin/auth_chain.py b/shadowsocks/obfsplugin/auth_chain.py index 66fce90..6619f4f 100644 --- a/shadowsocks/obfsplugin/auth_chain.py +++ b/shadowsocks/obfsplugin/auth_chain.py @@ -895,14 +895,14 @@ class auth_chain_f(auth_chain_e): self.data_size_list0 = [] random = xorshift128plus() # key xor with key_change_datetime_key - new_key = list(key) + new_key = bytearray(key) for i in range(0, 8): - new_key[i] = to_str(to_bytes(new_key[i]) ^ self.key_change_datetime_key_bytes[i]) + new_key[i] ^= self.key_change_datetime_key_bytes[i] random.init_from_bin(new_key) # 补全数组长为12~24-1 list_len = random.next() % (8 + 16) + (4 + 8) for i in range(0, list_len): - self.data_size_list0.append((int)(random.next() % 2340 % 2040 % 1440)) + self.data_size_list0.append(int(random.next() % 2340 % 2040 % 1440)) self.data_size_list0.sort() old_len = len(self.data_size_list0) self.check_and_patch_data_size(random)