* add mbedtls crypto wrapper. add tests files for new aead ciphers add custom lib path support fix some typo * fix forbidden ip list * rm crypto lib build files * remove crypto source * add xchacha20 test config * convert dos new line format to unix format * Fix help msgpull/841/head
@@ -16,6 +16,8 @@ before_install: | |||
- pip install pep8 pyflakes nose coverage PySocks | |||
- sudo tests/socksify/install.sh | |||
- sudo tests/libsodium/install.sh | |||
- sudo tests/libmbedtls/install.sh | |||
- sudo tests/libopenssl/install.sh | |||
- sudo tests/setup_tc.sh | |||
script: | |||
- tests/jenkins.sh |
@@ -7,8 +7,11 @@ | |||
"method":"aes-256-cfb", | |||
"local_address":"127.0.0.1", | |||
"fast_open":false, | |||
"dns_server":["8.8.8.8", 8.8.4.4], | |||
"tunnel_remote":"8.8.8.8", | |||
"dns_server":["8.8.8.8", "8.8.4.4"], | |||
"tunnel_remote_port":53, | |||
"tunnel_port":53 | |||
"tunnel_port":53, | |||
"libopenssl":"C:\\Program Files\\Git\\mingw64\\bin\\libeay32.dll", | |||
"libsodium":"/usr/local/lib/libsodium.so", | |||
"libmbedtls":"/usr/local/lib/libmbedcrypto.2.4.0.dylib" | |||
} |
@@ -71,7 +71,7 @@ libsodium = None | |||
sodium_loaded = False | |||
def load_sodium(): | |||
def load_sodium(path=None): | |||
""" | |||
Load libsodium helpers for nonce increment | |||
:return: None | |||
@@ -79,12 +79,14 @@ def load_sodium(): | |||
global libsodium, sodium_loaded | |||
libsodium = util.find_library('sodium', 'sodium_increment', | |||
'libsodium') | |||
'libsodium', path) | |||
if libsodium is None: | |||
print('load libsodium failed with path %s' % path) | |||
return | |||
if libsodium.sodium_init() < 0: | |||
libsodium = None | |||
print('sodium init failed') | |||
return | |||
libsodium.sodium_increment.restype = c_void_p | |||
@@ -139,7 +141,7 @@ class AeadCryptoBase(object): | |||
+--------+-----------+-----------+ | |||
""" | |||
def __init__(self, cipher_name, key, iv, op): | |||
def __init__(self, cipher_name, key, iv, op, crypto_path=None): | |||
self._op = int(op) | |||
self._salt = iv | |||
self._nlen = CIPHER_NONCE_LEN[cipher_name] | |||
@@ -158,7 +160,9 @@ class AeadCryptoBase(object): | |||
# load libsodium for nonce increment | |||
if not sodium_loaded: | |||
load_sodium() | |||
crypto_path = dict(crypto_path) if crypto_path else dict() | |||
path = crypto_path.get('sodium', None) | |||
load_sodium(path) | |||
def nonce_increment(self): | |||
""" | |||
@@ -171,6 +175,7 @@ class AeadCryptoBase(object): | |||
libsodium.sodium_increment(byref(self._nonce), c_int(self._nlen)) | |||
else: | |||
nonce_increment(self._nonce, self._nlen) | |||
# print("".join("%02x" % ord(b) for b in self._nonce)) | |||
def cipher_ctx_init(self): | |||
""" | |||
@@ -178,7 +183,6 @@ class AeadCryptoBase(object): | |||
:return: None | |||
""" | |||
self.nonce_increment() | |||
# print("".join("%02x" % ord(b) for b in self._nonce)) | |||
def aead_encrypt(self, data): | |||
""" | |||
@@ -331,4 +335,5 @@ def test_nonce_increment(): | |||
if __name__ == '__main__': | |||
load_sodium() | |||
test_nonce_increment() |
@@ -0,0 +1,481 @@ | |||
#!/usr/bin/env python | |||
# -*- coding: utf-8 -*- | |||
# | |||
# Void Copyright NO ONE | |||
# | |||
# Void License | |||
# | |||
# The code belongs to no one. Do whatever you want. | |||
# Forget about boring open source license. | |||
# | |||
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 | |||
from __future__ import absolute_import, division, print_function, \ | |||
with_statement | |||
from ctypes import c_char_p, c_int, c_size_t, byref,\ | |||
create_string_buffer, c_void_p | |||
from shadowsocks import common | |||
from shadowsocks.crypto import util | |||
from shadowsocks.crypto.aead import AeadCryptoBase | |||
__all__ = ['ciphers'] | |||
libmbedtls = None | |||
loaded = False | |||
buf = None | |||
buf_size = 2048 | |||
CIPHER_ENC_UNCHANGED = -1 | |||
# define MAX_KEY_LENGTH 64 | |||
# define MAX_NONCE_LENGTH 32 | |||
# typedef struct { | |||
# uint32_t init; | |||
# uint64_t counter; | |||
# cipher_evp_t *evp; | |||
# cipher_t *cipher; | |||
# buffer_t *chunk; | |||
# uint8_t salt[MAX_KEY_LENGTH]; | |||
# uint8_t skey[MAX_KEY_LENGTH]; | |||
# uint8_t nonce[MAX_NONCE_LENGTH]; | |||
# } cipher_ctx_t; | |||
# | |||
# sizeof(cipher_ctx_t) = 196 | |||
CIPHER_CTX_SIZE = 256 | |||
def load_mbedtls(crypto_path=None): | |||
global loaded, libmbedtls, buf | |||
crypto_path = dict(crypto_path) if crypto_path else dict() | |||
path = crypto_path.get('mbedtls', None) | |||
libmbedtls = util.find_library('mbedcrypto', | |||
'mbedtls_cipher_init', | |||
'libmbedcrypto', path) | |||
if libmbedtls is None: | |||
raise Exception('libmbedcrypto(mbedtls) not found with path %s' | |||
% path) | |||
libmbedtls.mbedtls_cipher_init.restype = None | |||
libmbedtls.mbedtls_cipher_free.restype = None | |||
libmbedtls.mbedtls_cipher_info_from_string.restype = c_void_p | |||
libmbedtls.mbedtls_cipher_info_from_string.argtypes = (c_char_p,) | |||
libmbedtls.mbedtls_cipher_setup.restype = c_int # 0 on success | |||
libmbedtls.mbedtls_cipher_setup.argtypes = (c_void_p, c_void_p) | |||
libmbedtls.mbedtls_cipher_setkey.restype = c_int # 0 on success | |||
libmbedtls.mbedtls_cipher_setkey.argtypes = ( | |||
c_void_p, # ctx | |||
c_char_p, # key | |||
c_int, # key_bitlen, not bytes | |||
c_int # op: 1 enc, 0 dec, -1 none | |||
) | |||
libmbedtls.mbedtls_cipher_set_iv.restype = c_int # 0 on success | |||
libmbedtls.mbedtls_cipher_set_iv.argtypes = ( | |||
c_void_p, # ctx | |||
c_char_p, # iv | |||
c_size_t # iv_len | |||
) | |||
libmbedtls.mbedtls_cipher_reset.restype = c_int # 0 on success | |||
libmbedtls.mbedtls_cipher_reset.argtypes = (c_void_p,) # ctx | |||
if hasattr(libmbedtls, 'mbedtls_cipher_update_ad'): | |||
libmbedtls.mbedtls_cipher_update_ad.restype = c_int # 0 on success | |||
libmbedtls.mbedtls_cipher_update_ad.argtypes = ( | |||
c_void_p, # ctx | |||
c_char_p, # ad | |||
c_size_t # ad_len | |||
) | |||
libmbedtls.mbedtls_cipher_update.restype = c_int # 0 on success | |||
libmbedtls.mbedtls_cipher_update.argtypes = ( | |||
c_void_p, # ctx | |||
c_char_p, # input | |||
c_size_t, # ilen, must be multiple of block size except last one | |||
c_void_p, # *output | |||
c_void_p # *olen | |||
) | |||
libmbedtls.mbedtls_cipher_finish.restype = c_int # 0 on success | |||
libmbedtls.mbedtls_cipher_finish.argtypes = ( | |||
c_void_p, # ctx | |||
c_void_p, # *output | |||
c_void_p # *olen | |||
) | |||
if hasattr(libmbedtls, 'mbedtls_cipher_write_tag'): | |||
libmbedtls.mbedtls_cipher_write_tag.restype = c_int # 0 on success | |||
libmbedtls.mbedtls_cipher_write_tag.argtypes = ( | |||
c_void_p, # ctx | |||
c_void_p, # *tag | |||
c_size_t # tag_len | |||
) | |||
libmbedtls.mbedtls_cipher_check_tag.restype = c_int # 0 on success | |||
libmbedtls.mbedtls_cipher_check_tag.argtypes = ( | |||
c_void_p, # ctx | |||
c_char_p, # tag | |||
c_size_t # tag_len | |||
) | |||
libmbedtls.mbedtls_cipher_crypt.restype = c_int # 0 on success | |||
libmbedtls.mbedtls_cipher_crypt.argtypes = ( | |||
c_void_p, # ctx | |||
c_char_p, # iv | |||
c_size_t, # iv_len, = 0 if iv = NULL | |||
c_char_p, # input | |||
c_size_t, # ilen | |||
c_void_p, # *output, no less than ilen + block_size | |||
c_void_p # *olen | |||
) | |||
if hasattr(libmbedtls, 'mbedtls_cipher_auth_encrypt'): | |||
libmbedtls.mbedtls_cipher_auth_encrypt.restype = c_int # 0 on success | |||
libmbedtls.mbedtls_cipher_auth_encrypt.argtypes = ( | |||
c_void_p, # ctx | |||
c_char_p, # iv | |||
c_size_t, # iv_len | |||
c_char_p, # ad | |||
c_size_t, # ad_len | |||
c_char_p, # input | |||
c_size_t, # ilen | |||
c_void_p, # *output, no less than ilen + block_size | |||
c_void_p, # *olen | |||
c_void_p, # *tag | |||
c_size_t # tag_len | |||
) | |||
libmbedtls.mbedtls_cipher_auth_decrypt.restype = c_int # 0 on success | |||
libmbedtls.mbedtls_cipher_auth_decrypt.argtypes = ( | |||
c_void_p, # ctx | |||
c_char_p, # iv | |||
c_size_t, # iv_len | |||
c_char_p, # ad | |||
c_size_t, # ad_len | |||
c_char_p, # input | |||
c_size_t, # ilen | |||
c_void_p, # *output, no less than ilen + block_size | |||
c_void_p, # *olen | |||
c_char_p, # tag | |||
c_size_t, # tag_len | |||
) | |||
buf = create_string_buffer(buf_size) | |||
loaded = True | |||
class MbedTLSCryptoBase(object): | |||
""" | |||
MbedTLS crypto base class | |||
""" | |||
def __init__(self, cipher_name, crypto_path=None): | |||
global loaded | |||
self._ctx = create_string_buffer(b'\0' * CIPHER_CTX_SIZE) | |||
self._cipher = None | |||
if not loaded: | |||
load_mbedtls(crypto_path) | |||
cipher_name = common.to_bytes(cipher_name.upper()) | |||
cipher = libmbedtls.mbedtls_cipher_info_from_string(cipher_name) | |||
if not cipher: | |||
raise Exception('cipher %s not found in libmbedtls' % cipher_name) | |||
libmbedtls.mbedtls_cipher_init(byref(self._ctx)) | |||
if libmbedtls.mbedtls_cipher_setup(byref(self._ctx), cipher): | |||
raise Exception('can not setup cipher') | |||
self._cipher = cipher | |||
self.encrypt_once = self.update | |||
self.decrypt_once = self.update | |||
def update(self, data): | |||
""" | |||
Encrypt/decrypt data | |||
:param data: str | |||
:return: str | |||
""" | |||
global buf_size, buf | |||
cipher_out_len = c_size_t(0) | |||
l = len(data) | |||
if buf_size < l: | |||
buf_size = l * 2 | |||
buf = create_string_buffer(buf_size) | |||
libmbedtls.mbedtls_cipher_update( | |||
byref(self._ctx), | |||
c_char_p(data), c_size_t(l), | |||
byref(buf), byref(cipher_out_len) | |||
) | |||
# buf is copied to a str object when we access buf.raw | |||
return buf.raw[:cipher_out_len.value] | |||
def __del__(self): | |||
self.clean() | |||
def clean(self): | |||
if self._ctx: | |||
libmbedtls.mbedtls_cipher_free(byref(self._ctx)) | |||
class MbedTLSAeadCrypto(MbedTLSCryptoBase, AeadCryptoBase): | |||
""" | |||
Implement mbedtls Aead mode: gcm | |||
""" | |||
def __init__(self, cipher_name, key, iv, op, crypto_path=None): | |||
if cipher_name[:len('mbedtls:')] == 'mbedtls:': | |||
cipher_name = cipher_name[len('mbedtls:'):] | |||
MbedTLSCryptoBase.__init__(self, cipher_name, crypto_path) | |||
AeadCryptoBase.__init__(self, cipher_name, key, iv, op, crypto_path) | |||
key_ptr = c_char_p(self._skey) | |||
r = libmbedtls.mbedtls_cipher_setkey( | |||
byref(self._ctx), | |||
key_ptr, c_int(len(key) * 8), | |||
c_int(op) | |||
) | |||
if r: | |||
self.clean() | |||
raise Exception('can not initialize cipher context') | |||
r = libmbedtls.mbedtls_cipher_reset(byref(self._ctx)) | |||
if r: | |||
self.clean() | |||
raise Exception('can not finish preparation of mbed TLS ' | |||
'cipher context') | |||
def cipher_ctx_init(self): | |||
""" | |||
Nonce + 1 | |||
:return: None | |||
""" | |||
AeadCryptoBase.nonce_increment(self) | |||
def set_tag(self, tag): | |||
""" | |||
Set tag before decrypt any data (update) | |||
:param tag: authenticated tag | |||
:return: None | |||
""" | |||
tag_len = self._tlen | |||
r = libmbedtls.mbedtls_cipher_check_tag( | |||
byref(self._ctx), | |||
c_char_p(tag), c_size_t(tag_len) | |||
) | |||
if not r: | |||
raise Exception('Set tag failed') | |||
def get_tag(self): | |||
""" | |||
Get authenticated tag, called after EVP_CipherFinal_ex | |||
:return: str | |||
""" | |||
tag_len = self._tlen | |||
tag_buf = create_string_buffer(tag_len) | |||
r = libmbedtls.mbedtls_cipher_write_tag( | |||
byref(self._ctx), | |||
byref(tag_buf), c_size_t(tag_len) | |||
) | |||
if not r: | |||
raise Exception('Get tag failed') | |||
return tag_buf.raw[:tag_len] | |||
def final(self): | |||
""" | |||
Finish encrypt/decrypt a chunk (<= 0x3FFF) | |||
:return: str | |||
""" | |||
global buf_size, buf | |||
cipher_out_len = c_size_t(0) | |||
r = libmbedtls.mbedtls_cipher_finish( | |||
byref(self._ctx), | |||
byref(buf), byref(cipher_out_len) | |||
) | |||
if not r: | |||
# print(self._nonce.raw, r, cipher_out_len) | |||
raise Exception('Finalize cipher failed') | |||
return buf.raw[:cipher_out_len.value] | |||
def aead_encrypt(self, data): | |||
""" | |||
Encrypt data with authenticate tag | |||
:param data: plain text | |||
:return: cipher text with tag | |||
""" | |||
global buf_size, buf | |||
plen = len(data) | |||
if buf_size < plen + self._tlen: | |||
buf_size = (plen + self._tlen) * 2 | |||
buf = create_string_buffer(buf_size) | |||
cipher_out_len = c_size_t(0) | |||
tag_buf = create_string_buffer(self._tlen) | |||
r = libmbedtls.mbedtls_cipher_auth_encrypt( | |||
byref(self._ctx), | |||
c_char_p(self._nonce.raw), c_size_t(self._nlen), | |||
None, c_size_t(0), | |||
c_char_p(data), c_size_t(plen), | |||
byref(buf), byref(cipher_out_len), | |||
byref(tag_buf), c_size_t(self._tlen) | |||
) | |||
assert cipher_out_len.value == plen | |||
if r: | |||
raise Exception('AEAD encrypt failed {0:#x}'.format(r)) | |||
self.cipher_ctx_init() | |||
return buf.raw[:cipher_out_len.value] + tag_buf.raw[:self._tlen] | |||
def aead_decrypt(self, data): | |||
""" | |||
Decrypt data and authenticate tag | |||
:param data: cipher text with tag | |||
:return: plain text | |||
""" | |||
global buf_size, buf | |||
cipher_out_len = c_size_t(0) | |||
plen = len(data) - self._tlen | |||
if buf_size < plen: | |||
buf_size = plen * 2 | |||
buf = create_string_buffer(buf_size) | |||
tag = data[plen:] | |||
r = libmbedtls.mbedtls_cipher_auth_decrypt( | |||
byref(self._ctx), | |||
c_char_p(self._nonce.raw), c_size_t(self._nlen), | |||
None, c_size_t(0), | |||
c_char_p(data), c_size_t(plen), | |||
byref(buf), byref(cipher_out_len), | |||
c_char_p(tag), c_size_t(self._tlen) | |||
) | |||
if r: | |||
raise Exception('AEAD encrypt failed {0:#x}'.format(r)) | |||
self.cipher_ctx_init() | |||
return buf.raw[:cipher_out_len.value] | |||
class MbedTLSStreamCrypto(MbedTLSCryptoBase): | |||
""" | |||
Crypto for stream modes: cfb, ofb, ctr | |||
""" | |||
def __init__(self, cipher_name, key, iv, op, crypto_path=None): | |||
if cipher_name[:len('mbedtls:')] == 'mbedtls:': | |||
cipher_name = cipher_name[len('mbedtls:'):] | |||
MbedTLSCryptoBase.__init__(self, cipher_name, crypto_path) | |||
key_ptr = c_char_p(key) | |||
iv_ptr = c_char_p(iv) | |||
r = libmbedtls.mbedtls_cipher_setkey( | |||
byref(self._ctx), | |||
key_ptr, c_int(len(key) * 8), | |||
c_int(op) | |||
) | |||
if r: | |||
self.clean() | |||
raise Exception('can not set cipher key') | |||
r = libmbedtls.mbedtls_cipher_set_iv( | |||
byref(self._ctx), | |||
iv_ptr, c_size_t(len(iv)) | |||
) | |||
if r: | |||
self.clean() | |||
raise Exception('can not set cipher iv') | |||
r = libmbedtls.mbedtls_cipher_reset(byref(self._ctx)) | |||
if r: | |||
self.clean() | |||
raise Exception('can not reset cipher') | |||
self.encrypt = self.update | |||
self.decrypt = self.update | |||
ciphers = { | |||
'mbedtls:aes-128-cfb128': (16, 16, MbedTLSStreamCrypto), | |||
'mbedtls:aes-192-cfb128': (24, 16, MbedTLSStreamCrypto), | |||
'mbedtls:aes-256-cfb128': (32, 16, MbedTLSStreamCrypto), | |||
'mbedtls:aes-128-ctr': (16, 16, MbedTLSStreamCrypto), | |||
'mbedtls:aes-192-ctr': (24, 16, MbedTLSStreamCrypto), | |||
'mbedtls:aes-256-ctr': (32, 16, MbedTLSStreamCrypto), | |||
'mbedtls:camellia-128-cfb128': (16, 16, MbedTLSStreamCrypto), | |||
'mbedtls:camellia-192-cfb128': (24, 16, MbedTLSStreamCrypto), | |||
'mbedtls:camellia-256-cfb128': (32, 16, MbedTLSStreamCrypto), | |||
# AEAD: iv_len = salt_len = key_len | |||
'mbedtls:aes-128-gcm': (16, 16, MbedTLSAeadCrypto), | |||
'mbedtls:aes-192-gcm': (24, 24, MbedTLSAeadCrypto), | |||
'mbedtls:aes-256-gcm': (32, 32, MbedTLSAeadCrypto), | |||
} | |||
def run_method(method): | |||
from shadowsocks.crypto import openssl | |||
print(method, ': [stream]', 32) | |||
cipher = MbedTLSStreamCrypto(method, b'k' * 32, b'i' * 16, 1) | |||
decipher = openssl.OpenSSLStreamCrypto(method, b'k' * 32, b'i' * 16, 0) | |||
util.run_cipher(cipher, decipher) | |||
def run_aead_method(method, key_len=16): | |||
from shadowsocks.crypto import openssl | |||
print(method, ': [payload][tag]', key_len) | |||
key_len = int(key_len) | |||
cipher = MbedTLSAeadCrypto(method, b'k' * key_len, b'i' * key_len, 1) | |||
decipher = openssl.OpenSSLAeadCrypto( | |||
method, | |||
b'k' * key_len, b'i' * key_len, 0 | |||
) | |||
util.run_cipher(cipher, decipher) | |||
def run_aead_method_chunk(method, key_len=16): | |||
from shadowsocks.crypto import openssl | |||
print(method, ': chunk([size][tag][payload][tag]', key_len) | |||
key_len = int(key_len) | |||
cipher = MbedTLSAeadCrypto(method, b'k' * key_len, b'i' * key_len, 1) | |||
decipher = openssl.OpenSSLAeadCrypto( | |||
method, | |||
b'k' * key_len, b'i' * key_len, 0 | |||
) | |||
cipher.encrypt_once = cipher.encrypt | |||
decipher.decrypt_once = decipher.decrypt | |||
util.run_cipher(cipher, decipher) | |||
def test_camellia_256_cfb(): | |||
run_method('camellia-256-cfb128') | |||
def test_aes_gcm(bits=128): | |||
method = "aes-{0}-gcm".format(bits) | |||
run_aead_method(method, bits / 8) | |||
def test_aes_gcm_chunk(bits=128): | |||
method = "aes-{0}-gcm".format(bits) | |||
run_aead_method_chunk(method, bits / 8) | |||
def test_aes_256_cfb(): | |||
run_method('aes-256-cfb128') | |||
def test_aes_256_ctr(): | |||
run_method('aes-256-ctr') | |||
if __name__ == '__main__': | |||
test_aes_256_cfb() | |||
test_camellia_256_cfb() | |||
test_aes_256_ctr() | |||
test_aes_gcm(128) | |||
test_aes_gcm(192) | |||
test_aes_gcm(256) | |||
test_aes_gcm_chunk(128) | |||
test_aes_gcm_chunk(192) | |||
test_aes_gcm_chunk(256) |
@@ -39,14 +39,16 @@ ctx_cleanup = None | |||
CIPHER_ENC_UNCHANGED = -1 | |||
def load_openssl(): | |||
def load_openssl(crypto_path=None): | |||
global loaded, libcrypto, libsodium, buf, ctx_cleanup | |||
crypto_path = dict(crypto_path) if crypto_path else dict() | |||
path = crypto_path.get('openssl', None) | |||
libcrypto = util.find_library(('crypto', 'eay32'), | |||
'EVP_get_cipherbyname', | |||
'libcrypto') | |||
'libcrypto', path) | |||
if libcrypto is None: | |||
raise Exception('libcrypto(OpenSSL) not found') | |||
raise Exception('libcrypto(OpenSSL) not found with path %s' % path) | |||
libcrypto.EVP_get_cipherbyname.restype = c_void_p | |||
libcrypto.EVP_CIPHER_CTX_new.restype = c_void_p | |||
@@ -89,11 +91,11 @@ class OpenSSLCryptoBase(object): | |||
""" | |||
OpenSSL crypto base class | |||
""" | |||
def __init__(self, cipher_name): | |||
def __init__(self, cipher_name, crypto_path=None): | |||
self._ctx = None | |||
self._cipher = None | |||
if not loaded: | |||
load_openssl() | |||
load_openssl(crypto_path) | |||
cipher_name = common.to_bytes(cipher_name) | |||
cipher = libcrypto.EVP_get_cipherbyname(cipher_name) | |||
if not cipher: | |||
@@ -140,9 +142,9 @@ class OpenSSLAeadCrypto(OpenSSLCryptoBase, AeadCryptoBase): | |||
""" | |||
Implement OpenSSL Aead mode: gcm, ocb | |||
""" | |||
def __init__(self, cipher_name, key, iv, op): | |||
super(OpenSSLAeadCrypto, self).__init__(cipher_name) | |||
AeadCryptoBase.__init__(self, cipher_name, key, iv, op) | |||
def __init__(self, cipher_name, key, iv, op, crypto_path=None): | |||
OpenSSLCryptoBase.__init__(self, cipher_name, crypto_path) | |||
AeadCryptoBase.__init__(self, cipher_name, key, iv, op, crypto_path) | |||
key_ptr = c_char_p(self._skey) | |||
r = libcrypto.EVP_CipherInit_ex( | |||
@@ -170,7 +172,7 @@ class OpenSSLAeadCrypto(OpenSSLCryptoBase, AeadCryptoBase): | |||
def cipher_ctx_init(self): | |||
""" | |||
Need init cipher context after EVP_CipherFinal_ex to reuse context | |||
:return: void | |||
:return: None | |||
""" | |||
iv_ptr = c_char_p(self._nonce.raw) | |||
r = libcrypto.EVP_CipherInit_ex( | |||
@@ -190,7 +192,7 @@ class OpenSSLAeadCrypto(OpenSSLCryptoBase, AeadCryptoBase): | |||
""" | |||
Set tag before decrypt any data (update) | |||
:param tag: authenticated tag | |||
:return: void | |||
:return: None | |||
""" | |||
tag_len = self._tlen | |||
r = libcrypto.EVP_CIPHER_CTX_ctrl( | |||
@@ -265,8 +267,8 @@ class OpenSSLStreamCrypto(OpenSSLCryptoBase): | |||
""" | |||
Crypto for stream modes: cfb, ofb, ctr | |||
""" | |||
def __init__(self, cipher_name, key, iv, op): | |||
super(OpenSSLStreamCrypto, self).__init__(cipher_name) | |||
def __init__(self, cipher_name, key, iv, op, crypto_path=None): | |||
OpenSSLCryptoBase.__init__(self, cipher_name, crypto_path) | |||
key_ptr = c_char_p(key) | |||
iv_ptr = c_char_p(iv) | |||
r = libcrypto.EVP_CipherInit_ex(self._ctx, self._cipher, None, | |||
@@ -282,9 +284,6 @@ ciphers = { | |||
'aes-128-cfb': (16, 16, OpenSSLStreamCrypto), | |||
'aes-192-cfb': (24, 16, OpenSSLStreamCrypto), | |||
'aes-256-cfb': (32, 16, OpenSSLStreamCrypto), | |||
'aes-128-gcm': (16, 16, OpenSSLAeadCrypto), | |||
'aes-192-gcm': (24, 24, OpenSSLAeadCrypto), | |||
'aes-256-gcm': (32, 32, OpenSSLAeadCrypto), | |||
'aes-128-ofb': (16, 16, OpenSSLStreamCrypto), | |||
'aes-192-ofb': (24, 16, OpenSSLStreamCrypto), | |||
'aes-256-ofb': (32, 16, OpenSSLStreamCrypto), | |||
@@ -307,6 +306,13 @@ ciphers = { | |||
'rc2-cfb': (16, 8, OpenSSLStreamCrypto), | |||
'rc4': (16, 0, OpenSSLStreamCrypto), | |||
'seed-cfb': (16, 16, OpenSSLStreamCrypto), | |||
# AEAD: iv_len = salt_len = key_len | |||
'aes-128-gcm': (16, 16, OpenSSLAeadCrypto), | |||
'aes-192-gcm': (24, 24, OpenSSLAeadCrypto), | |||
'aes-256-gcm': (32, 32, OpenSSLAeadCrypto), | |||
'aes-128-ocb': (16, 16, OpenSSLAeadCrypto), | |||
'aes-192-ocb': (24, 24, OpenSSLAeadCrypto), | |||
'aes-256-ocb': (32, 32, OpenSSLAeadCrypto), | |||
} | |||
@@ -353,10 +359,6 @@ def run_aead_method_chunk(method, key_len=16): | |||
util.run_cipher(cipher, decipher) | |||
def test_aes_128_cfb(): | |||
run_method('aes-128-cfb') | |||
def test_aes_gcm(bits=128): | |||
method = "aes-{0}-gcm".format(bits) | |||
run_aead_method(method, bits / 8) | |||
@@ -377,6 +379,10 @@ def test_aes_ocb_chunk(bits=128): | |||
run_aead_method_chunk(method, bits / 8) | |||
def test_aes_128_cfb(): | |||
run_method('aes-128-cfb') | |||
def test_aes_256_cfb(): | |||
run_method('aes-256-cfb') | |||
@@ -404,6 +410,7 @@ def test_rc4(): | |||
if __name__ == '__main__': | |||
test_aes_128_cfb() | |||
test_aes_256_cfb() | |||
test_aes_256_ofb() | |||
test_aes_gcm(128) | |||
test_aes_gcm(192) | |||
test_aes_gcm(256) |
@@ -23,13 +23,14 @@ from shadowsocks.crypto import openssl | |||
__all__ = ['ciphers'] | |||
def create_cipher(alg, key, iv, op, key_as_bytes=0, d=None, salt=None, | |||
def create_cipher(alg, key, iv, op, crypto_path=None, | |||
key_as_bytes=0, d=None, salt=None, | |||
i=1, padding=1): | |||
md5 = hashlib.md5() | |||
md5.update(key) | |||
md5.update(iv) | |||
rc4_key = md5.digest() | |||
return openssl.OpenSSLStreamCrypto(b'rc4', rc4_key, b'', op) | |||
return openssl.OpenSSLStreamCrypto(b'rc4', rc4_key, b'', op, crypto_path) | |||
ciphers = { |
@@ -17,7 +17,7 @@ | |||
from __future__ import absolute_import, division, print_function, \ | |||
with_statement | |||
from ctypes import c_char_p, c_int, c_ulonglong, byref, c_ulong, \ | |||
from ctypes import c_char_p, c_int, c_uint, c_ulonglong, byref, \ | |||
create_string_buffer, c_void_p | |||
from shadowsocks.crypto import util | |||
@@ -36,18 +36,21 @@ buf_size = 2048 | |||
BLOCK_SIZE = 64 | |||
def load_libsodium(): | |||
def load_libsodium(crypto_path=None): | |||
global loaded, libsodium, buf | |||
crypto_path = dict(crypto_path) if crypto_path else dict() | |||
path = crypto_path.get('sodium', None) | |||
if not aead.sodium_loaded: | |||
aead.load_sodium() | |||
aead.load_sodium(path) | |||
if aead.sodium_loaded: | |||
libsodium = aead.libsodium | |||
else: | |||
print('load libsodium again') | |||
print('load libsodium again with path %s' % path) | |||
libsodium = util.find_library('sodium', 'crypto_stream_salsa20_xor_ic', | |||
'libsodium') | |||
'libsodium', path) | |||
if libsodium is None: | |||
raise Exception('libsodium not found') | |||
@@ -55,39 +58,52 @@ def load_libsodium(): | |||
raise Exception('libsodium init failed') | |||
libsodium.crypto_stream_salsa20_xor_ic.restype = c_int | |||
libsodium.crypto_stream_salsa20_xor_ic.argtypes = (c_void_p, c_char_p, | |||
c_ulonglong, | |||
c_char_p, c_ulonglong, | |||
c_char_p) | |||
libsodium.crypto_stream_salsa20_xor_ic.argtypes = ( | |||
c_void_p, c_char_p, # cipher output, msg | |||
c_ulonglong, # msg len | |||
c_char_p, c_ulonglong, # nonce, uint64_t initial block counter | |||
c_char_p # key | |||
) | |||
libsodium.crypto_stream_chacha20_xor_ic.restype = c_int | |||
libsodium.crypto_stream_chacha20_xor_ic.argtypes = (c_void_p, c_char_p, | |||
c_ulonglong, | |||
c_char_p, c_ulonglong, | |||
c_char_p) | |||
libsodium.crypto_stream_chacha20_xor_ic.argtypes = ( | |||
c_void_p, c_char_p, | |||
c_ulonglong, | |||
c_char_p, c_ulonglong, | |||
c_char_p | |||
) | |||
if hasattr(libsodium, 'crypto_stream_xchacha20_xor_ic'): | |||
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 | |||
) | |||
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) | |||
libsodium.crypto_stream_chacha20_ietf_xor_ic.argtypes = ( | |||
c_void_p, c_char_p, | |||
c_ulonglong, | |||
c_char_p, | |||
c_uint, # uint32_t initial counter | |||
c_char_p | |||
) | |||
# chacha20-poly1305 | |||
libsodium.crypto_aead_chacha20poly1305_encrypt.restype = c_int | |||
libsodium.crypto_aead_chacha20poly1305_encrypt.argtypes = ( | |||
c_void_p, c_void_p, # c, clen | |||
c_void_p, c_void_p, # c, clen | |||
c_char_p, c_ulonglong, # m, mlen | |||
c_char_p, c_ulonglong, # ad, adlen | |||
c_char_p, # nsec, not used | |||
c_char_p, c_char_p # npub, k | |||
c_char_p, # nsec, not used | |||
c_char_p, c_char_p # npub, k | |||
) | |||
libsodium.crypto_aead_chacha20poly1305_decrypt.restype = c_int | |||
libsodium.crypto_aead_chacha20poly1305_decrypt.argtypes = ( | |||
c_void_p, c_void_p, # m, mlen | |||
c_char_p, # nsec, not used | |||
c_void_p, c_void_p, # m, mlen | |||
c_char_p, # nsec, not used | |||
c_char_p, c_ulonglong, # c, clen | |||
c_char_p, c_ulonglong, # ad, adlen | |||
c_char_p, c_char_p # npub, k | |||
c_char_p, c_char_p # npub, k | |||
) | |||
# chacha20-ietf-poly1305, same api structure as above | |||
@@ -154,9 +170,9 @@ def load_libsodium(): | |||
class SodiumCrypto(object): | |||
def __init__(self, cipher_name, key, iv, op): | |||
def __init__(self, cipher_name, key, iv, op, crypto_path=None): | |||
if not loaded: | |||
load_libsodium() | |||
load_libsodium(crypto_path) | |||
self.key = key | |||
self.iv = iv | |||
self.key_ptr = c_char_p(key) | |||
@@ -165,6 +181,11 @@ class SodiumCrypto(object): | |||
self.cipher = libsodium.crypto_stream_salsa20_xor_ic | |||
elif cipher_name == 'chacha20': | |||
self.cipher = libsodium.crypto_stream_chacha20_xor_ic | |||
elif cipher_name == 'xchacha20': | |||
if hasattr(libsodium, 'crypto_stream_xchacha20_xor_ic'): | |||
self.cipher = libsodium.crypto_stream_xchacha20_xor_ic | |||
else: | |||
raise Exception('Unsupported cipher') | |||
elif cipher_name == 'chacha20-ietf': | |||
self.cipher = libsodium.crypto_stream_chacha20_ietf_xor_ic | |||
else: | |||
@@ -198,32 +219,34 @@ class SodiumCrypto(object): | |||
class SodiumAeadCrypto(AeadCryptoBase): | |||
def __init__(self, cipher_name, key, iv, op): | |||
def __init__(self, cipher_name, key, iv, op, crypto_path=None): | |||
if not loaded: | |||
load_libsodium() | |||
AeadCryptoBase.__init__(self, cipher_name, key, iv, op) | |||
load_libsodium(crypto_path) | |||
AeadCryptoBase.__init__(self, cipher_name, key, iv, op, crypto_path) | |||
if cipher_name == 'chacha20-poly1305': | |||
self.encryptor = libsodium.crypto_aead_chacha20poly1305_encrypt | |||
self.decryptor = libsodium.crypto_aead_chacha20poly1305_decrypt | |||
elif cipher_name == 'chacha20-ietf-poly1305': | |||
self.encryptor = libsodium.\ | |||
self.encryptor = libsodium. \ | |||
crypto_aead_chacha20poly1305_ietf_encrypt | |||
self.decryptor = libsodium.\ | |||
self.decryptor = libsodium. \ | |||
crypto_aead_chacha20poly1305_ietf_decrypt | |||
elif cipher_name == 'xchacha20-ietf-poly1305': | |||
if hasattr(libsodium, | |||
'crypto_aead_xchacha20poly1305_ietf_encrypt'): | |||
self.encryptor = libsodium.\ | |||
self.encryptor = libsodium. \ | |||
crypto_aead_xchacha20poly1305_ietf_encrypt | |||
self.decryptor = libsodium.\ | |||
self.decryptor = libsodium. \ | |||
crypto_aead_xchacha20poly1305_ietf_decrypt | |||
else: | |||
raise Exception('Unknown cipher') | |||
raise Exception('Unsupported cipher') | |||
elif cipher_name == 'sodium:aes-256-gcm': | |||
if hasattr(libsodium, 'crypto_aead_aes256gcm_encrypt'): | |||
self.encryptor = libsodium.crypto_aead_aes256gcm_encrypt | |||
self.decryptor = libsodium.crypto_aead_aes256gcm_decrypt | |||
else: | |||
raise Exception('Unsupported cipher') | |||
else: | |||
raise Exception('Unknown cipher') | |||
@@ -269,7 +292,7 @@ class SodiumAeadCrypto(AeadCryptoBase): | |||
raise Exception("Decrypt failed") | |||
if cipher_out_len.value != clen - self._tlen: | |||
raise Exception("Encrypt failed") | |||
raise Exception("Decrypt failed") | |||
self.cipher_ctx_init() | |||
return buf.raw[:cipher_out_len.value] | |||
@@ -278,7 +301,9 @@ class SodiumAeadCrypto(AeadCryptoBase): | |||
ciphers = { | |||
'salsa20': (32, 8, SodiumCrypto), | |||
'chacha20': (32, 8, SodiumCrypto), | |||
'xchacha20': (32, 24, SodiumCrypto), | |||
'chacha20-ietf': (32, 12, SodiumCrypto), | |||
# AEAD: iv_len = salt_len = key_len | |||
'chacha20-poly1305': (32, 32, SodiumAeadCrypto), | |||
'chacha20-ietf-poly1305': (32, 32, SodiumAeadCrypto), | |||
'xchacha20-ietf-poly1305': (32, 32, SodiumAeadCrypto), | |||
@@ -286,26 +311,31 @@ ciphers = { | |||
} | |||
def test_salsa20(): | |||
print("Test salsa20") | |||
cipher = SodiumCrypto('salsa20', b'k' * 32, b'i' * 16, 1) | |||
decipher = SodiumCrypto('salsa20', b'k' * 32, b'i' * 16, 0) | |||
def test_chacha20(): | |||
print("Test chacha20") | |||
cipher = SodiumCrypto('chacha20', b'k' * 32, b'i' * 16, 1) | |||
decipher = SodiumCrypto('chacha20', b'k' * 32, b'i' * 16, 0) | |||
util.run_cipher(cipher, decipher) | |||
def test_chacha20(): | |||
def test_xchacha20(): | |||
print("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) | |||
print("Test chacha20") | |||
cipher = SodiumCrypto('chacha20', b'k' * 32, b'i' * 16, 1) | |||
decipher = SodiumCrypto('chacha20', b'k' * 32, b'i' * 16, 0) | |||
def test_salsa20(): | |||
print("Test salsa20") | |||
cipher = SodiumCrypto('salsa20', b'k' * 32, b'i' * 16, 1) | |||
decipher = SodiumCrypto('salsa20', b'k' * 32, b'i' * 16, 0) | |||
util.run_cipher(cipher, decipher) | |||
def test_chacha20_ietf(): | |||
print("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) | |||
@@ -314,7 +344,6 @@ def test_chacha20_ietf(): | |||
def test_chacha20_poly1305(): | |||
print("Test chacha20-poly1305 [payload][tag]") | |||
cipher = SodiumAeadCrypto('chacha20-poly1305', | |||
b'k' * 32, b'i' * 32, 1) | |||
@@ -325,7 +354,6 @@ def test_chacha20_poly1305(): | |||
def test_chacha20_poly1305_chunk(): | |||
print("Test chacha20-poly1305 chunk [size][tag][payload][tag]") | |||
cipher = SodiumAeadCrypto('chacha20-poly1305', | |||
b'k' * 32, b'i' * 32, 1) | |||
@@ -339,7 +367,6 @@ def test_chacha20_poly1305_chunk(): | |||
def test_chacha20_ietf_poly1305(): | |||
print("Test chacha20-ietf-poly1305 [payload][tag]") | |||
cipher = SodiumAeadCrypto('chacha20-ietf-poly1305', | |||
b'k' * 32, b'i' * 32, 1) | |||
@@ -350,7 +377,6 @@ def test_chacha20_ietf_poly1305(): | |||
def test_chacha20_ietf_poly1305_chunk(): | |||
print("Test chacha20-ietf-poly1305 chunk [size][tag][payload][tag]") | |||
cipher = SodiumAeadCrypto('chacha20-ietf-poly1305', | |||
b'k' * 32, b'i' * 32, 1) | |||
@@ -364,7 +390,6 @@ def test_chacha20_ietf_poly1305_chunk(): | |||
def test_aes_256_gcm(): | |||
print("Test sodium:aes-256-gcm [payload][tag]") | |||
cipher = SodiumAeadCrypto('sodium:aes-256-gcm', | |||
b'k' * 32, b'i' * 32, 1) | |||
@@ -375,7 +400,6 @@ def test_aes_256_gcm(): | |||
def test_aes_256_gcm_chunk(): | |||
print("Test sodium:aes-256-gcm chunk [size][tag][payload][tag]") | |||
cipher = SodiumAeadCrypto('sodium:aes-256-gcm', | |||
b'k' * 32, b'i' * 32, 1) | |||
@@ -390,6 +414,7 @@ def test_aes_256_gcm_chunk(): | |||
if __name__ == '__main__': | |||
test_chacha20() | |||
test_xchacha20() | |||
test_salsa20() | |||
test_chacha20_ietf() | |||
test_chacha20_poly1305() |
@@ -55,7 +55,7 @@ def init_table(key): | |||
class TableCipher(object): | |||
def __init__(self, cipher_name, key, iv, op): | |||
def __init__(self, cipher_name, key, iv, op, crypto_path=None): | |||
self._encrypt_table, self._decrypt_table = init_table(key) | |||
self._op = op | |||
self.encrypt = self.update |
@@ -41,9 +41,27 @@ def find_library_nt(name): | |||
return results | |||
def find_library(possible_lib_names, search_symbol, library_name): | |||
import ctypes.util | |||
def load_library(path, search_symbol, library_name): | |||
from ctypes import CDLL | |||
try: | |||
lib = CDLL(path) | |||
if hasattr(lib, search_symbol): | |||
logging.info('loading %s from %s', library_name, path) | |||
return lib | |||
else: | |||
logging.warn('can\'t find symbol %s in %s', search_symbol, | |||
path) | |||
except Exception: | |||
pass | |||
return None | |||
def find_library(possible_lib_names, search_symbol, library_name, | |||
custom_path=None): | |||
import ctypes.util | |||
if custom_path: | |||
return load_library(custom_path, search_symbol, library_name) | |||
paths = [] | |||
@@ -81,16 +99,9 @@ def find_library(possible_lib_names, search_symbol, library_name): | |||
if files: | |||
paths.extend(files) | |||
for path in paths: | |||
try: | |||
lib = CDLL(path) | |||
if hasattr(lib, search_symbol): | |||
logging.info('loading %s from %s', library_name, path) | |||
return lib | |||
else: | |||
logging.warn('can\'t find symbol %s in %s', search_symbol, | |||
path) | |||
except Exception: | |||
pass | |||
lib = load_library(path, search_symbol, library_name) | |||
if lib: | |||
return lib | |||
return None | |||
@@ -23,7 +23,7 @@ import hashlib | |||
import logging | |||
from shadowsocks import common | |||
from shadowsocks.crypto import rc4_md5, openssl, sodium, table | |||
from shadowsocks.crypto import rc4_md5, openssl, mbedtls, sodium, table | |||
CIPHER_ENC_ENCRYPTION = 1 | |||
@@ -36,6 +36,7 @@ METHOD_INFO_CRYPTO = 2 | |||
method_supported = {} | |||
method_supported.update(rc4_md5.ciphers) | |||
method_supported.update(openssl.ciphers) | |||
method_supported.update(mbedtls.ciphers) | |||
method_supported.update(sodium.ciphers) | |||
method_supported.update(table.ciphers) | |||
@@ -46,8 +47,8 @@ def random_string(length): | |||
cached_keys = {} | |||
def try_cipher(key, method=None): | |||
Cryptor(key, method) | |||
def try_cipher(key, method=None, crypto_path=None): | |||
Cryptor(key, method, crypto_path) | |||
def EVP_BytesToKey(password, key_len, iv_len): | |||
@@ -75,7 +76,14 @@ def EVP_BytesToKey(password, key_len, iv_len): | |||
class Cryptor(object): | |||
def __init__(self, password, method): | |||
def __init__(self, password, method, crypto_path=None): | |||
""" | |||
Crypto wrapper | |||
:param password: str cipher password | |||
:param method: str cipher | |||
:param crypto_path: dict or none | |||
{'openssl': path, 'sodium': path, 'mbedtls': path} | |||
""" | |||
self.password = password | |||
self.key = None | |||
self.method = method | |||
@@ -83,6 +91,7 @@ class Cryptor(object): | |||
self.cipher_iv = b'' | |||
self.decipher = None | |||
self.decipher_iv = None | |||
self.crypto_path = crypto_path | |||
method = method.lower() | |||
self._method_info = Cryptor.get_method_info(method) | |||
if self._method_info: | |||
@@ -118,7 +127,7 @@ class Cryptor(object): | |||
if op == CIPHER_ENC_ENCRYPTION: | |||
# this iv is for cipher not decipher | |||
self.cipher_iv = iv | |||
return m[METHOD_INFO_CRYPTO](method, key, iv, op) | |||
return m[METHOD_INFO_CRYPTO](method, key, iv, op, self.crypto_path) | |||
def encrypt(self, buf): | |||
if len(buf) == 0: | |||
@@ -139,7 +148,7 @@ class Cryptor(object): | |||
self.decipher = self.get_cipher( | |||
self.password, self.method, | |||
CIPHER_ENC_DECRYPTION, | |||
iv=decipher_iv | |||
decipher_iv | |||
) | |||
buf = buf[decipher_iv_len:] | |||
if len(buf) == 0: | |||
@@ -158,30 +167,30 @@ def gen_key_iv(password, method): | |||
return key, iv, m | |||
def encrypt_all_m(key, iv, m, method, data): | |||
def encrypt_all_m(key, iv, m, method, data, crypto_path=None): | |||
result = [iv] | |||
cipher = m(method, key, iv, 1) | |||
cipher = m(method, key, iv, 1, crypto_path) | |||
result.append(cipher.encrypt_once(data)) | |||
return b''.join(result) | |||
def decrypt_all(password, method, data): | |||
def decrypt_all(password, method, data, crypto_path=None): | |||
result = [] | |||
method = method.lower() | |||
(key, iv, m) = gen_key_iv(password, method) | |||
iv = data[:len(iv)] | |||
data = data[len(iv):] | |||
cipher = m(method, key, iv, CIPHER_ENC_DECRYPTION) | |||
cipher = m(method, key, iv, CIPHER_ENC_DECRYPTION, crypto_path) | |||
result.append(cipher.decrypt_once(data)) | |||
return b''.join(result), key, iv | |||
def encrypt_all(password, method, data): | |||
def encrypt_all(password, method, data, crypto_path=None): | |||
result = [] | |||
method = method.lower() | |||
(key, iv, m) = gen_key_iv(password, method) | |||
result.append(iv) | |||
cipher = m(method, key, iv, CIPHER_ENC_ENCRYPTION) | |||
cipher = m(method, key, iv, CIPHER_ENC_ENCRYPTION, crypto_path) | |||
result.append(cipher.encrypt_once(data)) | |||
return b''.join(result) | |||
@@ -189,6 +198,7 @@ def encrypt_all(password, method, data): | |||
CIPHERS_TO_TEST = [ | |||
'aes-128-cfb', | |||
'aes-256-cfb', | |||
'aes-256-gcm', | |||
'rc4-md5', | |||
'salsa20', | |||
'chacha20', |
@@ -71,6 +71,7 @@ class Manager(object): | |||
port_password = config['port_password'] | |||
del config['port_password'] | |||
config['crypto_path'] = config.get('crypto_path', dict()) | |||
for port, password in port_password.items(): | |||
a_config = config.copy() | |||
a_config['server_port'] = int(port) |
@@ -201,7 +201,12 @@ def check_config(config, is_local): | |||
config['dns_server'] = to_str(config['dns_server']) | |||
logging.info('Specified DNS server: %s' % config['dns_server']) | |||
cryptor.try_cipher(config['password'], config['method']) | |||
config['crypto_path'] = {'openssl': config['libopenssl'], | |||
'mbedtls': config['libmbedtls'], | |||
'sodium': config['libsodium']} | |||
cryptor.try_cipher(config['password'], config['method'], | |||
config['crypto_path']) | |||
def get_config(is_local): | |||
@@ -212,12 +217,12 @@ def get_config(is_local): | |||
if is_local: | |||
shortopts = 'hd:s:b:p:k:l:m:c:t:vqa' | |||
longopts = ['help', 'fast-open', 'pid-file=', 'log-file=', 'user=', | |||
'version'] | |||
'libopenssl=', 'libmbedtls=', 'libsodium=', 'version'] | |||
else: | |||
shortopts = 'hd:s:p:k:m:c:t:vqa' | |||
longopts = ['help', 'fast-open', 'pid-file=', 'log-file=', 'workers=', | |||
'forbidden-ip=', 'user=', 'manager-address=', 'version', | |||
'prefer-ipv6'] | |||
'libopenssl=', 'libmbedtls=', 'libsodium=', 'prefer-ipv6'] | |||
try: | |||
config_path = find_config() | |||
optlist, args = getopt.getopt(sys.argv[1:], shortopts, longopts) | |||
@@ -261,10 +266,16 @@ def get_config(is_local): | |||
config['timeout'] = int(value) | |||
elif key == '--fast-open': | |||
config['fast_open'] = True | |||
elif key == '--libopenssl': | |||
config['libopenssl'] = to_str(value) | |||
elif key == '--libmbedtls': | |||
config['libmbedtls'] = to_str(value) | |||
elif key == '--libsodium': | |||
config['libsodium'] = to_str(value) | |||
elif key == '--workers': | |||
config['workers'] = int(value) | |||
elif key == '--manager-address': | |||
config['manager_address'] = value | |||
config['manager_address'] = to_str(value) | |||
elif key == '--user': | |||
config['user'] = to_str(value) | |||
elif key == '--forbidden-ip': | |||
@@ -313,11 +324,14 @@ def get_config(is_local): | |||
config['one_time_auth'] = config.get('one_time_auth', False) | |||
config['prefer_ipv6'] = config.get('prefer_ipv6', False) | |||
config['server_port'] = config.get('server_port', 8388) | |||
config['dns_server'] = config.get('dns_server', None) | |||
config['libopenssl'] = config.get('libopenssl', None) | |||
config['libmbedtls'] = config.get('libmbedtls', None) | |||
config['libsodium'] = config.get('libsodium', None) | |||
config['tunnel_remote'] = to_str(config.get('tunnel_remote', '8.8.8.8')) | |||
config['tunnel_remote_port'] = config.get('tunnel_remote_port', 53) | |||
config['tunnel_port'] = config.get('tunnel_port', 53) | |||
config['dns_server'] = config.get('dns_server', None) | |||
logging.getLogger('').handlers = [] | |||
logging.addLevelName(VERBOSE_LEVEL, 'VERBOSE') | |||
@@ -364,29 +378,38 @@ Proxy options: | |||
-m METHOD encryption method, default: aes-256-cfb | |||
Sodium: | |||
chacha20-poly1305, chacha20-ietf-poly1305, | |||
*xchacha20-ietf-poly1305, | |||
xchacha20-ietf-poly1305, | |||
sodium:aes-256-gcm, | |||
salsa20, chacha20, chacha20-ietf. | |||
OpenSSL:(* v1.1) | |||
*aes-128-ocb, *aes-192-ocb, *aes-256-ocb, | |||
aes-128-gcm, aes-192-gcm, aes-256-gcm, | |||
aes-128-cfb, aes-192-cfb, aes-256-cfb, | |||
aes-128-ctr, aes-192-ctr, aes-256-ctr, | |||
camellia-128-cfb, camellia-192-cfb, | |||
camellia-256-cfb, | |||
Sodium 1.0.12: | |||
xchacha20 | |||
OpenSSL: | |||
aes-{128|192|256}-gcm, aes-{128|192|256}-cfb, | |||
aes-{128|192|256}-ofb, aes-{128|192|256}-ctr, | |||
camellia-{128|192|256}-cfb, | |||
bf-cfb, cast5-cfb, des-cfb, idea-cfb, | |||
rc2-cfb, seed-cfb, | |||
rc4, rc4-md5, table. | |||
OpenSSL 1.1: | |||
aes-{128|192|256}-ocb | |||
mbedTLS: | |||
mbedtls:aes-{128|192|256}-cfb128, | |||
mbedtls:aes-{128|192|256}-ctr, | |||
mbedtls:camellia-{128|192|256}-cfb128, | |||
mbedtls:aes-{128|192|256}-gcm | |||
-t TIMEOUT timeout in seconds, default: 300 | |||
-a ONE_TIME_AUTH one time auth | |||
--fast-open use TCP_FASTOPEN, requires Linux 3.7+ | |||
--libopenssl=PATH custom openssl crypto lib path | |||
--libmbedtls=PATH custom mbedtls crypto lib path | |||
--libsodium=PATH custom sodium crypto lib path | |||
General options: | |||
-h, --help show this help message and exit | |||
-d start/stop/restart daemon mode | |||
--pid-file PID_FILE pid file for daemon mode | |||
--log-file LOG_FILE log file for daemon mode | |||
--user USER username to run as | |||
--pid-file=PID_FILE pid file for daemon mode | |||
--log-file=LOG_FILE log file for daemon mode | |||
--user=USER username to run as | |||
-v, -vv verbose mode | |||
-q, -qq quiet mode, only show warnings/errors | |||
--version show version information | |||
@@ -409,26 +432,35 @@ Proxy options: | |||
-m METHOD encryption method, default: aes-256-cfb | |||
Sodium: | |||
chacha20-poly1305, chacha20-ietf-poly1305, | |||
*xchacha20-ietf-poly1305, | |||
xchacha20-ietf-poly1305, | |||
sodium:aes-256-gcm, | |||
salsa20, chacha20, chacha20-ietf. | |||
OpenSSL:(* v1.1) | |||
*aes-128-ocb, *aes-192-ocb, *aes-256-ocb, | |||
aes-128-gcm, aes-192-gcm, aes-256-gcm, | |||
aes-128-cfb, aes-192-cfb, aes-256-cfb, | |||
aes-128-ctr, aes-192-ctr, aes-256-ctr, | |||
camellia-128-cfb, camellia-192-cfb, | |||
camellia-256-cfb, | |||
Sodium 1.0.12: | |||
xchacha20 | |||
OpenSSL: | |||
aes-{128|192|256}-gcm, aes-{128|192|256}-cfb, | |||
aes-{128|192|256}-ofb, aes-{128|192|256}-ctr, | |||
camellia-{128|192|256}-cfb, | |||
bf-cfb, cast5-cfb, des-cfb, idea-cfb, | |||
rc2-cfb, seed-cfb, | |||
rc4, rc4-md5, table. | |||
OpenSSL 1.1: | |||
aes-{128|192|256}-ocb | |||
mbedTLS: | |||
mbedtls:aes-{128|192|256}-cfb128, | |||
mbedtls:aes-{128|192|256}-ctr, | |||
mbedtls:camellia-{128|192|256}-cfb128, | |||
mbedtls:aes-{128|192|256}-gcm | |||
-t TIMEOUT timeout in seconds, default: 300 | |||
-a ONE_TIME_AUTH one time auth | |||
--fast-open use TCP_FASTOPEN, requires Linux 3.7+ | |||
--workers WORKERS number of workers, available on Unix/Linux | |||
--forbidden-ip IPLIST comma seperated IP list forbidden to connect | |||
--manager-address ADDR optional server manager UDP address, see wiki | |||
--workers=WORKERS number of workers, available on Unix/Linux | |||
--forbidden-ip=IPLIST comma seperated IP list forbidden to connect | |||
--manager-address=ADDR optional server manager UDP address, see wiki | |||
--prefer-ipv6 resolve ipv6 address first | |||
--libopenssl=PATH custom openssl crypto lib path | |||
--libmbedtls=PATH custom mbedtls crypto lib path | |||
--libsodium=PATH custom sodium crypto lib path | |||
General options: | |||
-h, --help show this help message and exit |
@@ -93,6 +93,8 @@ WAIT_STATUS_WRITING = 2 | |||
WAIT_STATUS_READWRITING = WAIT_STATUS_READING | WAIT_STATUS_WRITING | |||
BUF_SIZE = 32 * 1024 | |||
UP_STREAM_BUF_SIZE = 16 * 1024 | |||
DOWN_STREAM_BUF_SIZE = 32 * 1024 | |||
# helper exceptions for TCPRelayHandler | |||
@@ -126,7 +128,8 @@ class TCPRelayHandler(object): | |||
self._is_local = is_local | |||
self._stage = STAGE_INIT | |||
self._cryptor = cryptor.Cryptor(config['password'], | |||
config['method']) | |||
config['method'], | |||
config['crypto_path']) | |||
self._ota_enable = config.get('one_time_auth', False) | |||
self._ota_enable_session = self._ota_enable | |||
self._ota_buff_head = b'' | |||
@@ -553,8 +556,12 @@ class TCPRelayHandler(object): | |||
return | |||
is_local = self._is_local | |||
data = None | |||
if is_local: | |||
buf_size = UP_STREAM_BUF_SIZE | |||
else: | |||
buf_size = DOWN_STREAM_BUF_SIZE | |||
try: | |||
data = self._local_sock.recv(BUF_SIZE) | |||
data = self._local_sock.recv(buf_size) | |||
except (OSError, IOError) as e: | |||
if eventloop.errno_from_exception(e) in \ | |||
(errno.ETIMEDOUT, errno.EAGAIN, errno.EWOULDBLOCK): | |||
@@ -586,8 +593,12 @@ class TCPRelayHandler(object): | |||
def _on_remote_read(self): | |||
# handle all remote read events | |||
data = None | |||
if self._is_local: | |||
buf_size = UP_STREAM_BUF_SIZE | |||
else: | |||
buf_size = DOWN_STREAM_BUF_SIZE | |||
try: | |||
data = self._remote_sock.recv(BUF_SIZE) | |||
data = self._remote_sock.recv(buf_size) | |||
except (OSError, IOError) as e: | |||
if eventloop.errno_from_exception(e) in \ |
@@ -115,6 +115,8 @@ class UDPRelay(object): | |||
self._closed = False | |||
self._sockets = set() | |||
self._forbidden_iplist = config.get('forbidden_ip') | |||
self._crypto_path = config['crypto_path'] | |||
addrs = socket.getaddrinfo(self._listen_addr, self._listen_port, 0, | |||
socket.SOCK_DGRAM, socket.SOL_UDP) | |||
if len(addrs) == 0: | |||
@@ -174,7 +176,7 @@ class UDPRelay(object): | |||
try: | |||
data, key, iv = cryptor.decrypt_all(self._password, | |||
self._method, | |||
data) | |||
data, self._crypto_path) | |||
except Exception: | |||
logging.debug('UDP handle_server: decrypt data failed') | |||
return | |||
@@ -241,7 +243,8 @@ class UDPRelay(object): | |||
if self._ota_enable_session: | |||
data = self._ota_chunk_data_gen(key, iv, data) | |||
try: | |||
data = cryptor.encrypt_all_m(key, iv, m, self._method, data) | |||
data = cryptor.encrypt_all_m(key, iv, m, self._method, data, | |||
self._crypto_path) | |||
except Exception: | |||
logging.debug("UDP handle_server: encrypt data failed") | |||
return | |||
@@ -275,7 +278,8 @@ class UDPRelay(object): | |||
data = pack_addr(r_addr[0]) + struct.pack('>H', r_addr[1]) + data | |||
try: | |||
response = cryptor.encrypt_all(self._password, | |||
self._method, data) | |||
self._method, data, | |||
self._crypto_path) | |||
except Exception: | |||
logging.debug("UDP handle_client: encrypt data failed") | |||
return | |||
@@ -284,7 +288,8 @@ class UDPRelay(object): | |||
else: | |||
try: | |||
data, key, iv = cryptor.decrypt_all(self._password, | |||
self._method, data) | |||
self._method, data, | |||
self._crypto_path) | |||
except Exception: | |||
logging.debug('UDP handle_client: decrypt data failed') | |||
return |
@@ -1,10 +1,10 @@ | |||
{ | |||
"server":"127.0.0.1", | |||
"server_port":8388, | |||
"local_port":1081, | |||
"password":"aes_password", | |||
"timeout":60, | |||
"method":"aes-256-cfb1", | |||
"local_address":"127.0.0.1", | |||
"fast_open":false | |||
} | |||
{ | |||
"server":"127.0.0.1", | |||
"server_port":8388, | |||
"local_port":1081, | |||
"password":"aes_password", | |||
"timeout":60, | |||
"method":"aes-256-cfb1", | |||
"local_address":"127.0.0.1", | |||
"fast_open":false | |||
} |
@@ -1,10 +1,10 @@ | |||
{ | |||
"server":"127.0.0.1", | |||
"server_port":8388, | |||
"local_port":1081, | |||
"password":"aes_password", | |||
"timeout":60, | |||
"method":"aes-256-cfb8", | |||
"local_address":"127.0.0.1", | |||
"fast_open":false | |||
} | |||
{ | |||
"server":"127.0.0.1", | |||
"server_port":8388, | |||
"local_port":1081, | |||
"password":"aes_password", | |||
"timeout":60, | |||
"method":"aes-256-cfb8", | |||
"local_address":"127.0.0.1", | |||
"fast_open":false | |||
} |
@@ -1,10 +1,10 @@ | |||
{ | |||
"server":"127.0.0.1", | |||
"server_port":8388, | |||
"local_port":1081, | |||
"password":"aes_password", | |||
"timeout":60, | |||
"method":"aes-256-ctr", | |||
"local_address":"127.0.0.1", | |||
"fast_open":false | |||
} | |||
{ | |||
"server":"127.0.0.1", | |||
"server_port":8388, | |||
"local_port":1081, | |||
"password":"aes_password", | |||
"timeout":60, | |||
"method":"aes-256-ctr", | |||
"local_address":"127.0.0.1", | |||
"fast_open":false | |||
} |
@@ -0,0 +1,10 @@ | |||
{ | |||
"server":"127.0.0.1", | |||
"server_port":8388, | |||
"local_port":1081, | |||
"password":"aes_password", | |||
"timeout":60, | |||
"method":"aes-256-gcm", | |||
"local_address":"127.0.0.1", | |||
"fast_open":false | |||
} |
@@ -0,0 +1,11 @@ | |||
{ | |||
"server":"127.0.0.1", | |||
"server_port":8388, | |||
"local_port":1081, | |||
"password":"aes_password", | |||
"timeout":60, | |||
"method":"aes-256-ocb", | |||
"local_address":"127.0.0.1", | |||
"fast_open":false, | |||
"libopenssl":"/usr/local/lib/libcrypto.so.1.1" | |||
} |
@@ -0,0 +1,10 @@ | |||
{ | |||
"server":"127.0.0.1", | |||
"server_port":8388, | |||
"local_port":1081, | |||
"password":"aes_password", | |||
"timeout":60, | |||
"method":"aes-256-ofb", | |||
"local_address":"127.0.0.1", | |||
"fast_open":false | |||
} |
@@ -1,10 +1,10 @@ | |||
{ | |||
"server":"127.0.0.1", | |||
"server_port":8388, | |||
"local_port":1081, | |||
"password":"aes_password", | |||
"timeout":60, | |||
"method":"aes-256-cfb", | |||
"local_address":"127.0.0.1", | |||
"fast_open":false | |||
} | |||
{ | |||
"server":"127.0.0.1", | |||
"server_port":8388, | |||
"local_port":1081, | |||
"password":"aes_password", | |||
"timeout":60, | |||
"method":"aes-256-cfb", | |||
"local_address":"127.0.0.1", | |||
"fast_open":false | |||
} |
@@ -0,0 +1,10 @@ | |||
{ | |||
"server":"127.0.0.1", | |||
"server_port":8388, | |||
"local_port":1081, | |||
"password":"camellia_password", | |||
"timeout":60, | |||
"method":"camellia-256-cfb", | |||
"local_address":"127.0.0.1", | |||
"fast_open":false | |||
} |
@@ -0,0 +1,10 @@ | |||
{ | |||
"server":"127.0.0.1", | |||
"server_port":8388, | |||
"local_port":1081, | |||
"password":"salsa20_password", | |||
"timeout":60, | |||
"method":"chacha20-ietf-poly1305", | |||
"local_address":"127.0.0.1", | |||
"fast_open":false | |||
} |
@@ -1,10 +1,10 @@ | |||
{ | |||
"server":"127.0.0.1", | |||
"server_port":8388, | |||
"local_port":1081, | |||
"password":"salsa20_password", | |||
"timeout":60, | |||
"method":"chacha20-ietf", | |||
"local_address":"127.0.0.1", | |||
"fast_open":false | |||
} | |||
{ | |||
"server":"127.0.0.1", | |||
"server_port":8388, | |||
"local_port":1081, | |||
"password":"salsa20_password", | |||
"timeout":60, | |||
"method":"chacha20-ietf", | |||
"local_address":"127.0.0.1", | |||
"fast_open":false | |||
} |
@@ -0,0 +1,10 @@ | |||
{ | |||
"server":"127.0.0.1", | |||
"server_port":8388, | |||
"local_port":1081, | |||
"password":"salsa20_password", | |||
"timeout":60, | |||
"method":"chacha20-poly1305", | |||
"local_address":"127.0.0.1", | |||
"fast_open":false | |||
} |
@@ -1,10 +1,10 @@ | |||
{ | |||
"server":"127.0.0.1", | |||
"server_port":8388, | |||
"local_port":1081, | |||
"password":"salsa20_password", | |||
"timeout":60, | |||
"method":"chacha20", | |||
"local_address":"127.0.0.1", | |||
"fast_open":false | |||
} | |||
{ | |||
"server":"127.0.0.1", | |||
"server_port":8388, | |||
"local_port":1081, | |||
"password":"chacha20_password", | |||
"timeout":60, | |||
"method":"chacha20", | |||
"local_address":"127.0.0.1", | |||
"fast_open":false | |||
} |
@@ -1,10 +1,10 @@ | |||
{ | |||
"server":["127.0.0.1", "127.0.0.1"], | |||
"server_port":8388, | |||
"local_port":1081, | |||
"password":"aes_password", | |||
"timeout":60, | |||
"method":"aes-256-cfb", | |||
"local_address":"127.0.0.1", | |||
"fast_open":false | |||
} | |||
{ | |||
"server":["127.0.0.1", "127.0.0.1"], | |||
"server_port":8388, | |||
"local_port":1081, | |||
"password":"aes_password", | |||
"timeout":60, | |||
"method":"aes-256-cfb", | |||
"local_address":"127.0.0.1", | |||
"fast_open":false | |||
} |
@@ -1,10 +1,10 @@ | |||
{ | |||
"server":"127.0.0.1", | |||
"server_port":8388, | |||
"local_port":1081, | |||
"password":"fastopen_password", | |||
"timeout":60, | |||
"method":"aes-256-cfb", | |||
"local_address":"127.0.0.1", | |||
"fast_open":true | |||
} | |||
{ | |||
"server":"127.0.0.1", | |||
"server_port":8388, | |||
"local_port":1081, | |||
"password":"fastopen_password", | |||
"timeout":60, | |||
"method":"aes-256-cfb", | |||
"local_address":"127.0.0.1", | |||
"fast_open":true | |||
} |
@@ -1,10 +1,10 @@ | |||
{ | |||
"server":"127.0.0.1", | |||
"server_port":8388, | |||
"local_port":1081, | |||
"password":"aes_password", | |||
"timeout":15, | |||
"method":"aes-256-cfb", | |||
"local_address":"127.0.0.1", | |||
"fast_open":false | |||
} | |||
{ | |||
"server":"127.0.0.1", | |||
"server_port":8388, | |||
"local_port":1081, | |||
"password":"aes_password", | |||
"timeout":15, | |||
"method":"aes-256-cfb", | |||
"local_address":"127.0.0.1", | |||
"fast_open":false | |||
} |
@@ -1,10 +1,10 @@ | |||
{ | |||
"server":"::1", | |||
"server_port":8388, | |||
"local_port":1081, | |||
"password":"aes_password", | |||
"timeout":60, | |||
"method":"aes-256-cfb", | |||
"local_address":"127.0.0.1", | |||
"fast_open":false | |||
} | |||
{ | |||
"server":"::1", | |||
"server_port":8388, | |||
"local_port":1081, | |||
"password":"aes_password", | |||
"timeout":60, | |||
"method":"aes-256-cfb", | |||
"local_address":"127.0.0.1", | |||
"fast_open":false | |||
} |
@@ -1,10 +1,10 @@ | |||
{ | |||
"server":"::", | |||
"server_port":8388, | |||
"local_port":1081, | |||
"password":"aes_password", | |||
"timeout":60, | |||
"method":"aes-256-cfb", | |||
"local_address":"127.0.0.1", | |||
"fast_open":false | |||
} | |||
{ | |||
"server":"::", | |||
"server_port":8388, | |||
"local_port":1081, | |||
"password":"aes_password", | |||
"timeout":60, | |||
"method":"aes-256-cfb", | |||
"local_address":"127.0.0.1", | |||
"fast_open":false | |||
} |
@@ -33,12 +33,25 @@ run_test coverage run tests/nose_plugin.py -v | |||
run_test python setup.py sdist | |||
run_test tests/test_daemon.sh | |||
run_test python tests/test.py --with-coverage -c tests/aes.json | |||
run_test python tests/test.py --with-coverage -c tests/mbedtls-aes.json | |||
run_test python tests/test.py --with-coverage -c tests/aes-gcm.json | |||
run_test python tests/test.py --with-coverage -c tests/aes-ocb.json | |||
run_test python tests/test.py --with-coverage -c tests/mbedtls-aes-gcm.json | |||
run_test python tests/test.py --with-coverage -c tests/aes-ctr.json | |||
run_test python tests/test.py --with-coverage -c tests/mbedtls-aes-ctr.json | |||
run_test python tests/test.py --with-coverage -c tests/aes-cfb1.json | |||
run_test python tests/test.py --with-coverage -c tests/aes-cfb8.json | |||
run_test python tests/test.py --with-coverage -c tests/aes-ofb.json | |||
run_test python tests/test.py --with-coverage -c tests/camellia.json | |||
run_test python tests/test.py --with-coverage -c tests/mbedtls-camellia.json | |||
run_test python tests/test.py --with-coverage -c tests/rc4-md5.json | |||
run_test python tests/test.py --with-coverage -c tests/salsa20.json | |||
run_test python tests/test.py --with-coverage -c tests/chacha20.json | |||
run_test python tests/test.py --with-coverage -c tests/xchacha20.json | |||
run_test python tests/test.py --with-coverage -c tests/chacha20-ietf.json | |||
run_test python tests/test.py --with-coverage -c tests/chacha20-poly1305.json | |||
run_test python tests/test.py --with-coverage -c tests/xchacha20-ietf-poly1305.json | |||
run_test python tests/test.py --with-coverage -c tests/chacha20-ietf-poly1305.json | |||
run_test python tests/test.py --with-coverage -c tests/table.json | |||
run_test python tests/test.py --with-coverage -c tests/server-multi-ports.json | |||
run_test python tests/test.py --with-coverage -s tests/aes.json -c tests/client-multi-server-ip.json | |||
@@ -52,6 +65,15 @@ run_test python tests/test.py --with-coverage -b "-m rc4-md5 -k testrc4 -s 127.0 | |||
run_test python tests/test.py --with-coverage -b "-m aes-256-cfb -k testrc4 -s 127.0.0.1 -p 8388 --workers 1" -a "-m aes-256-cfb -k testrc4 -s 127.0.0.1 -p 8388 -l 1081 -t 30 -qq -b 127.0.0.1" | |||
run_test python tests/test.py --with-coverage --should-fail --url="http://127.0.0.1/" -b "-m aes-256-cfb -k testrc4 -s 127.0.0.1 -p 8388 --forbidden-ip=127.0.0.1,::1,8.8.8.8" -a "-m aes-256-cfb -k testrc4 -s 127.0.0.1 -p 8388 -l 1081 -t 30 -b 127.0.0.1" | |||
# test custom lib path | |||
run_test python tests/test.py --with-coverage --url="http://127.0.0.1/" -b "-m aes-256-cfb -k testrc4 -s 127.0.0.1 -p 8388 --forbidden-ip= --libopenssl=/usr/local/lib/libcrypto.so" -a "-m aes-256-cfb -k testrc4 -s 127.0.0.1 -p 8388 -l 1081 -t 30 -b 127.0.0.1 --libopenssl=/usr/local/lib/libcrypto.so" | |||
run_test python tests/test.py --with-coverage --url="http://127.0.0.1/" -b "-m mbedtls:aes-256-cfb128 -k testrc4 -s 127.0.0.1 -p 8388 --forbidden-ip= --libmbedtls=/usr/local/lib/libmbedcrypto.so" -a "-m mbedtls:aes-256-cfb128 -k testrc4 -s 127.0.0.1 -p 8388 -l 1081 -t 30 -b 127.0.0.1 --libmbedtls=/usr/local/lib/libmbedcrypto.so" | |||
run_test python tests/test.py --with-coverage --url="http://127.0.0.1/" -b "-m chacha20-ietf -k testrc4 -s 127.0.0.1 -p 8388 --forbidden-ip= --libsodium=/usr/local/lib/libsodium.so" -a "-m chacha20-ietf -k testrc4 -s 127.0.0.1 -p 8388 -l 1081 -t 30 -b 127.0.0.1 --libsodium=/usr/local/lib/libsodium.so" | |||
run_test python tests/test.py --with-coverage --should-fail --url="http://127.0.0.1/" -b "-m aes-256-cfb -k testrc4 -s 127.0.0.1 -p 8388 --forbidden-ip= --libopenssl=invalid_path" -a "-m aes-256-cfb -k testrc4 -s 127.0.0.1 -p 8388 -l 1081 -t 30 -b 127.0.0.1 --libopenssl=invalid_path" | |||
run_test python tests/test.py --with-coverage --should-fail --url="http://127.0.0.1/" -b "-m chacha20-ietf -k testrc4 -s 127.0.0.1 -p 8388 --forbidden-ip= --libsodium=invalid_path" -a "-m chacha20-ietf -k testrc4 -s 127.0.0.1 -p 8388 -l 1081 -t 30 -b 127.0.0.1 --libsodium=invalid_path" | |||
run_test python tests/test.py --with-coverage --should-fail --url="http://127.0.0.1/" -b "-m mbedtls:aes-256-cfb -k testrc4 -s 127.0.0.1 -p 8388 --forbidden-ip= --libmbedtls=invalid_path" -a "-m mbedtls:aes-256-cfb -k testrc4 -s 127.0.0.1 -p 8388 -l 1081 -t 30 -b 127.0.0.1 --libmbedtls=invalid_path" | |||
# test if DNS works | |||
run_test python tests/test.py --with-coverage -c tests/aes.json --url="https://clients1.google.com/generate_204" | |||
@@ -0,0 +1,12 @@ | |||
#!/bin/bash | |||
MBEDTLS_VER=2.4.2 | |||
if [ ! -d mbedtls-$MBEDTLS_VER ]; then | |||
wget https://tls.mbed.org/download/mbedtls-$MBEDTLS_VER-gpl.tgz || exit 1 | |||
tar xf mbedtls-$MBEDTLS_VER-gpl.tgz || exit 1 | |||
fi | |||
pushd mbedtls-$MBEDTLS_VER | |||
make SHARED=1 CFLAGS=-fPIC && sudo make install || exit 1 | |||
sudo ldconfig | |||
popd | |||
rm -rf mbedtls-$MBEDTLS_VER || exit 1 |
@@ -0,0 +1,12 @@ | |||
#!/bin/bash | |||
OPENSSL_VER=1.1.0e | |||
if [ ! -d openssl-$OPENSSL_VER ]; then | |||
wget https://www.openssl.org/source/openssl-$OPENSSL_VER.tar.gz || exit 1 | |||
tar xf openssl-$OPENSSL_VER.tar.gz || exit 1 | |||
fi | |||
pushd openssl-$OPENSSL_VER | |||
./config && make && sudo make install || exit 1 | |||
# sudo ldconfig # test multiple libcrypto | |||
popd | |||
rm -rf openssl-$OPENSSL_VER || exit 1 |
@@ -1,10 +1,11 @@ | |||
#!/bin/bash | |||
if [ ! -d libsodium-1.0.11 ]; then | |||
wget https://github.com/jedisct1/libsodium/releases/download/1.0.11/libsodium-1.0.11.tar.gz || exit 1 | |||
tar xf libsodium-1.0.11.tar.gz || exit 1 | |||
if [ ! -d libsodium-1.0.12 ]; then | |||
wget https://github.com/jedisct1/libsodium/releases/download/1.0.12/libsodium-1.0.12.tar.gz || exit 1 | |||
tar xf libsodium-1.0.12.tar.gz || exit 1 | |||
fi | |||
pushd libsodium-1.0.11 | |||
pushd libsodium-1.0.12 | |||
./configure && make -j2 && make install || exit 1 | |||
sudo ldconfig | |||
popd | |||
rm -rf libsodium-1.0.12 || exit 1 |
@@ -0,0 +1,10 @@ | |||
{ | |||
"server":"127.0.0.1", | |||
"server_port":8388, | |||
"local_port":1081, | |||
"password":"aes_password", | |||
"timeout":60, | |||
"method":"mbedtls:aes-256-ctr", | |||
"local_address":"127.0.0.1", | |||
"fast_open":false | |||
} |
@@ -0,0 +1,10 @@ | |||
{ | |||
"server":"127.0.0.1", | |||
"server_port":8388, | |||
"local_port":1081, | |||
"password":"aes_password", | |||
"timeout":60, | |||
"method":"mbedtls:aes-256-gcm", | |||
"local_address":"127.0.0.1", | |||
"fast_open":false | |||
} |
@@ -0,0 +1,10 @@ | |||
{ | |||
"server":"127.0.0.1", | |||
"server_port":8388, | |||
"local_port":1081, | |||
"password":"aes_password", | |||
"timeout":60, | |||
"method":"mbedtls:aes-256-cfb128", | |||
"local_address":"127.0.0.1", | |||
"fast_open":false | |||
} |
@@ -0,0 +1,10 @@ | |||
{ | |||
"server":"127.0.0.1", | |||
"server_port":8388, | |||
"local_port":1081, | |||
"password":"camellia_password", | |||
"timeout":60, | |||
"method":"mbedtls:camellia-256-cfb128", | |||
"local_address":"127.0.0.1", | |||
"fast_open":false | |||
} |
@@ -1,11 +1,11 @@ | |||
{ | |||
"server":"127.0.0.1", | |||
"server_port":8388, | |||
"local_port":1081, | |||
"password":"aes_password", | |||
"timeout":60, | |||
"method":"rc4-md5", | |||
"local_address":"127.0.0.1", | |||
"fast_open":false, | |||
"one_time_auth":true | |||
} | |||
{ | |||
"server":"127.0.0.1", | |||
"server_port":8388, | |||
"local_port":1081, | |||
"password":"aes_password", | |||
"timeout":60, | |||
"method":"rc4-md5", | |||
"local_address":"127.0.0.1", | |||
"fast_open":false, | |||
"one_time_auth":true | |||
} |
@@ -1,10 +1,10 @@ | |||
{ | |||
"server":"127.0.0.1", | |||
"server_port":8388, | |||
"local_port":1081, | |||
"password":"aes_password", | |||
"timeout":60, | |||
"method":"rc4-md5", | |||
"local_address":"127.0.0.1", | |||
"fast_open":false | |||
} | |||
{ | |||
"server":"127.0.0.1", | |||
"server_port":8388, | |||
"local_port":1081, | |||
"password":"aes_password", | |||
"timeout":60, | |||
"method":"rc4-md5", | |||
"local_address":"127.0.0.1", | |||
"fast_open":false | |||
} |
@@ -1,10 +1,10 @@ | |||
{ | |||
"server":"127.0.0.1", | |||
"server_port":8388, | |||
"local_port":1081, | |||
"password":"salsa20_password", | |||
"timeout":60, | |||
"method":"salsa20-ctr", | |||
"local_address":"127.0.0.1", | |||
"fast_open":false | |||
} | |||
{ | |||
"server":"127.0.0.1", | |||
"server_port":8388, | |||
"local_port":1081, | |||
"password":"salsa20_password", | |||
"timeout":60, | |||
"method":"salsa20-ctr", | |||
"local_address":"127.0.0.1", | |||
"fast_open":false | |||
} |
@@ -1,10 +1,10 @@ | |||
{ | |||
"server":"127.0.0.1", | |||
"server_port":8388, | |||
"local_port":1081, | |||
"password":"salsa20_password", | |||
"timeout":60, | |||
"method":"salsa20", | |||
"local_address":"127.0.0.1", | |||
"fast_open":false | |||
} | |||
{ | |||
"server":"127.0.0.1", | |||
"server_port":8388, | |||
"local_port":1081, | |||
"password":"salsa20_password", | |||
"timeout":60, | |||
"method":"salsa20", | |||
"local_address":"127.0.0.1", | |||
"fast_open":false | |||
} |
@@ -1,11 +1,11 @@ | |||
{ | |||
"server":"127.0.0.1", | |||
"server_port":8388, | |||
"local_port":1081, | |||
"password":"aes_password", | |||
"timeout":60, | |||
"method":"aes-256-cfb", | |||
"local_address":"127.0.0.1", | |||
"fast_open":false, | |||
"dns_server": ["8.8.8.8","8.8.4.4"] | |||
} | |||
{ | |||
"server":"127.0.0.1", | |||
"server_port":8388, | |||
"local_port":1081, | |||
"password":"aes_password", | |||
"timeout":60, | |||
"method":"aes-256-cfb", | |||
"local_address":"127.0.0.1", | |||
"fast_open":false, | |||
"dns_server": ["8.8.8.8","8.8.4.4"] | |||
} |
@@ -1,10 +1,10 @@ | |||
{ | |||
"server":"127.0.0.1", | |||
"server_port":8388, | |||
"local_port":1081, | |||
"password":"table_password", | |||
"timeout":60, | |||
"method":"table", | |||
"local_address":"127.0.0.1", | |||
"fast_open":false | |||
} | |||
{ | |||