Add mbedtls wrapper, custom crypto lib path, test files (#803)
* 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 msg
This commit is contained in:
parent
1222fb19a6
commit
0f4e3fa00c
48 changed files with 1088 additions and 326 deletions
|
@ -16,6 +16,8 @@ before_install:
|
||||||
- pip install pep8 pyflakes nose coverage PySocks
|
- pip install pep8 pyflakes nose coverage PySocks
|
||||||
- sudo tests/socksify/install.sh
|
- sudo tests/socksify/install.sh
|
||||||
- sudo tests/libsodium/install.sh
|
- sudo tests/libsodium/install.sh
|
||||||
|
- sudo tests/libmbedtls/install.sh
|
||||||
|
- sudo tests/libopenssl/install.sh
|
||||||
- sudo tests/setup_tc.sh
|
- sudo tests/setup_tc.sh
|
||||||
script:
|
script:
|
||||||
- tests/jenkins.sh
|
- tests/jenkins.sh
|
||||||
|
|
|
@ -7,8 +7,11 @@
|
||||||
"method":"aes-256-cfb",
|
"method":"aes-256-cfb",
|
||||||
"local_address":"127.0.0.1",
|
"local_address":"127.0.0.1",
|
||||||
"fast_open":false,
|
"fast_open":false,
|
||||||
"dns_server":["8.8.8.8", 8.8.4.4],
|
|
||||||
"tunnel_remote":"8.8.8.8",
|
"tunnel_remote":"8.8.8.8",
|
||||||
|
"dns_server":["8.8.8.8", "8.8.4.4"],
|
||||||
"tunnel_remote_port":53,
|
"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
|
sodium_loaded = False
|
||||||
|
|
||||||
|
|
||||||
def load_sodium():
|
def load_sodium(path=None):
|
||||||
"""
|
"""
|
||||||
Load libsodium helpers for nonce increment
|
Load libsodium helpers for nonce increment
|
||||||
:return: None
|
:return: None
|
||||||
|
@ -79,12 +79,14 @@ def load_sodium():
|
||||||
global libsodium, sodium_loaded
|
global libsodium, sodium_loaded
|
||||||
|
|
||||||
libsodium = util.find_library('sodium', 'sodium_increment',
|
libsodium = util.find_library('sodium', 'sodium_increment',
|
||||||
'libsodium')
|
'libsodium', path)
|
||||||
if libsodium is None:
|
if libsodium is None:
|
||||||
|
print('load libsodium failed with path %s' % path)
|
||||||
return
|
return
|
||||||
|
|
||||||
if libsodium.sodium_init() < 0:
|
if libsodium.sodium_init() < 0:
|
||||||
libsodium = None
|
libsodium = None
|
||||||
|
print('sodium init failed')
|
||||||
return
|
return
|
||||||
|
|
||||||
libsodium.sodium_increment.restype = c_void_p
|
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._op = int(op)
|
||||||
self._salt = iv
|
self._salt = iv
|
||||||
self._nlen = CIPHER_NONCE_LEN[cipher_name]
|
self._nlen = CIPHER_NONCE_LEN[cipher_name]
|
||||||
|
@ -158,7 +160,9 @@ class AeadCryptoBase(object):
|
||||||
|
|
||||||
# load libsodium for nonce increment
|
# load libsodium for nonce increment
|
||||||
if not sodium_loaded:
|
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):
|
def nonce_increment(self):
|
||||||
"""
|
"""
|
||||||
|
@ -171,6 +175,7 @@ class AeadCryptoBase(object):
|
||||||
libsodium.sodium_increment(byref(self._nonce), c_int(self._nlen))
|
libsodium.sodium_increment(byref(self._nonce), c_int(self._nlen))
|
||||||
else:
|
else:
|
||||||
nonce_increment(self._nonce, self._nlen)
|
nonce_increment(self._nonce, self._nlen)
|
||||||
|
# print("".join("%02x" % ord(b) for b in self._nonce))
|
||||||
|
|
||||||
def cipher_ctx_init(self):
|
def cipher_ctx_init(self):
|
||||||
"""
|
"""
|
||||||
|
@ -178,7 +183,6 @@ class AeadCryptoBase(object):
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
self.nonce_increment()
|
self.nonce_increment()
|
||||||
# print("".join("%02x" % ord(b) for b in self._nonce))
|
|
||||||
|
|
||||||
def aead_encrypt(self, data):
|
def aead_encrypt(self, data):
|
||||||
"""
|
"""
|
||||||
|
@ -331,4 +335,5 @@ def test_nonce_increment():
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
load_sodium()
|
||||||
test_nonce_increment()
|
test_nonce_increment()
|
||||||
|
|
481
shadowsocks/crypto/mbedtls.py
Normal file
481
shadowsocks/crypto/mbedtls.py
Normal file
|
@ -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
|
CIPHER_ENC_UNCHANGED = -1
|
||||||
|
|
||||||
|
|
||||||
def load_openssl():
|
def load_openssl(crypto_path=None):
|
||||||
global loaded, libcrypto, libsodium, buf, ctx_cleanup
|
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'),
|
libcrypto = util.find_library(('crypto', 'eay32'),
|
||||||
'EVP_get_cipherbyname',
|
'EVP_get_cipherbyname',
|
||||||
'libcrypto')
|
'libcrypto', path)
|
||||||
if libcrypto is None:
|
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_get_cipherbyname.restype = c_void_p
|
||||||
libcrypto.EVP_CIPHER_CTX_new.restype = c_void_p
|
libcrypto.EVP_CIPHER_CTX_new.restype = c_void_p
|
||||||
|
@ -89,11 +91,11 @@ class OpenSSLCryptoBase(object):
|
||||||
"""
|
"""
|
||||||
OpenSSL crypto base class
|
OpenSSL crypto base class
|
||||||
"""
|
"""
|
||||||
def __init__(self, cipher_name):
|
def __init__(self, cipher_name, crypto_path=None):
|
||||||
self._ctx = None
|
self._ctx = None
|
||||||
self._cipher = None
|
self._cipher = None
|
||||||
if not loaded:
|
if not loaded:
|
||||||
load_openssl()
|
load_openssl(crypto_path)
|
||||||
cipher_name = common.to_bytes(cipher_name)
|
cipher_name = common.to_bytes(cipher_name)
|
||||||
cipher = libcrypto.EVP_get_cipherbyname(cipher_name)
|
cipher = libcrypto.EVP_get_cipherbyname(cipher_name)
|
||||||
if not cipher:
|
if not cipher:
|
||||||
|
@ -140,9 +142,9 @@ class OpenSSLAeadCrypto(OpenSSLCryptoBase, AeadCryptoBase):
|
||||||
"""
|
"""
|
||||||
Implement OpenSSL Aead mode: gcm, ocb
|
Implement OpenSSL Aead mode: gcm, ocb
|
||||||
"""
|
"""
|
||||||
def __init__(self, cipher_name, key, iv, op):
|
def __init__(self, cipher_name, key, iv, op, crypto_path=None):
|
||||||
super(OpenSSLAeadCrypto, self).__init__(cipher_name)
|
OpenSSLCryptoBase.__init__(self, cipher_name, crypto_path)
|
||||||
AeadCryptoBase.__init__(self, cipher_name, key, iv, op)
|
AeadCryptoBase.__init__(self, cipher_name, key, iv, op, crypto_path)
|
||||||
|
|
||||||
key_ptr = c_char_p(self._skey)
|
key_ptr = c_char_p(self._skey)
|
||||||
r = libcrypto.EVP_CipherInit_ex(
|
r = libcrypto.EVP_CipherInit_ex(
|
||||||
|
@ -170,7 +172,7 @@ class OpenSSLAeadCrypto(OpenSSLCryptoBase, AeadCryptoBase):
|
||||||
def cipher_ctx_init(self):
|
def cipher_ctx_init(self):
|
||||||
"""
|
"""
|
||||||
Need init cipher context after EVP_CipherFinal_ex to reuse context
|
Need init cipher context after EVP_CipherFinal_ex to reuse context
|
||||||
:return: void
|
:return: None
|
||||||
"""
|
"""
|
||||||
iv_ptr = c_char_p(self._nonce.raw)
|
iv_ptr = c_char_p(self._nonce.raw)
|
||||||
r = libcrypto.EVP_CipherInit_ex(
|
r = libcrypto.EVP_CipherInit_ex(
|
||||||
|
@ -190,7 +192,7 @@ class OpenSSLAeadCrypto(OpenSSLCryptoBase, AeadCryptoBase):
|
||||||
"""
|
"""
|
||||||
Set tag before decrypt any data (update)
|
Set tag before decrypt any data (update)
|
||||||
:param tag: authenticated tag
|
:param tag: authenticated tag
|
||||||
:return: void
|
:return: None
|
||||||
"""
|
"""
|
||||||
tag_len = self._tlen
|
tag_len = self._tlen
|
||||||
r = libcrypto.EVP_CIPHER_CTX_ctrl(
|
r = libcrypto.EVP_CIPHER_CTX_ctrl(
|
||||||
|
@ -265,8 +267,8 @@ class OpenSSLStreamCrypto(OpenSSLCryptoBase):
|
||||||
"""
|
"""
|
||||||
Crypto for stream modes: cfb, ofb, ctr
|
Crypto for stream modes: cfb, ofb, ctr
|
||||||
"""
|
"""
|
||||||
def __init__(self, cipher_name, key, iv, op):
|
def __init__(self, cipher_name, key, iv, op, crypto_path=None):
|
||||||
super(OpenSSLStreamCrypto, self).__init__(cipher_name)
|
OpenSSLCryptoBase.__init__(self, cipher_name, crypto_path)
|
||||||
key_ptr = c_char_p(key)
|
key_ptr = c_char_p(key)
|
||||||
iv_ptr = c_char_p(iv)
|
iv_ptr = c_char_p(iv)
|
||||||
r = libcrypto.EVP_CipherInit_ex(self._ctx, self._cipher, None,
|
r = libcrypto.EVP_CipherInit_ex(self._ctx, self._cipher, None,
|
||||||
|
@ -282,9 +284,6 @@ ciphers = {
|
||||||
'aes-128-cfb': (16, 16, OpenSSLStreamCrypto),
|
'aes-128-cfb': (16, 16, OpenSSLStreamCrypto),
|
||||||
'aes-192-cfb': (24, 16, OpenSSLStreamCrypto),
|
'aes-192-cfb': (24, 16, OpenSSLStreamCrypto),
|
||||||
'aes-256-cfb': (32, 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-128-ofb': (16, 16, OpenSSLStreamCrypto),
|
||||||
'aes-192-ofb': (24, 16, OpenSSLStreamCrypto),
|
'aes-192-ofb': (24, 16, OpenSSLStreamCrypto),
|
||||||
'aes-256-ofb': (32, 16, OpenSSLStreamCrypto),
|
'aes-256-ofb': (32, 16, OpenSSLStreamCrypto),
|
||||||
|
@ -307,6 +306,13 @@ ciphers = {
|
||||||
'rc2-cfb': (16, 8, OpenSSLStreamCrypto),
|
'rc2-cfb': (16, 8, OpenSSLStreamCrypto),
|
||||||
'rc4': (16, 0, OpenSSLStreamCrypto),
|
'rc4': (16, 0, OpenSSLStreamCrypto),
|
||||||
'seed-cfb': (16, 16, 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)
|
util.run_cipher(cipher, decipher)
|
||||||
|
|
||||||
|
|
||||||
def test_aes_128_cfb():
|
|
||||||
run_method('aes-128-cfb')
|
|
||||||
|
|
||||||
|
|
||||||
def test_aes_gcm(bits=128):
|
def test_aes_gcm(bits=128):
|
||||||
method = "aes-{0}-gcm".format(bits)
|
method = "aes-{0}-gcm".format(bits)
|
||||||
run_aead_method(method, bits / 8)
|
run_aead_method(method, bits / 8)
|
||||||
|
@ -377,6 +379,10 @@ def test_aes_ocb_chunk(bits=128):
|
||||||
run_aead_method_chunk(method, bits / 8)
|
run_aead_method_chunk(method, bits / 8)
|
||||||
|
|
||||||
|
|
||||||
|
def test_aes_128_cfb():
|
||||||
|
run_method('aes-128-cfb')
|
||||||
|
|
||||||
|
|
||||||
def test_aes_256_cfb():
|
def test_aes_256_cfb():
|
||||||
run_method('aes-256-cfb')
|
run_method('aes-256-cfb')
|
||||||
|
|
||||||
|
@ -404,6 +410,7 @@ def test_rc4():
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
test_aes_128_cfb()
|
test_aes_128_cfb()
|
||||||
test_aes_256_cfb()
|
test_aes_256_cfb()
|
||||||
|
test_aes_256_ofb()
|
||||||
test_aes_gcm(128)
|
test_aes_gcm(128)
|
||||||
test_aes_gcm(192)
|
test_aes_gcm(192)
|
||||||
test_aes_gcm(256)
|
test_aes_gcm(256)
|
||||||
|
|
|
@ -23,13 +23,14 @@ from shadowsocks.crypto import openssl
|
||||||
__all__ = ['ciphers']
|
__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):
|
i=1, padding=1):
|
||||||
md5 = hashlib.md5()
|
md5 = hashlib.md5()
|
||||||
md5.update(key)
|
md5.update(key)
|
||||||
md5.update(iv)
|
md5.update(iv)
|
||||||
rc4_key = md5.digest()
|
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 = {
|
ciphers = {
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
from __future__ import absolute_import, division, print_function, \
|
from __future__ import absolute_import, division, print_function, \
|
||||||
with_statement
|
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
|
create_string_buffer, c_void_p
|
||||||
|
|
||||||
from shadowsocks.crypto import util
|
from shadowsocks.crypto import util
|
||||||
|
@ -36,18 +36,21 @@ buf_size = 2048
|
||||||
BLOCK_SIZE = 64
|
BLOCK_SIZE = 64
|
||||||
|
|
||||||
|
|
||||||
def load_libsodium():
|
def load_libsodium(crypto_path=None):
|
||||||
global loaded, libsodium, buf
|
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:
|
if not aead.sodium_loaded:
|
||||||
aead.load_sodium()
|
aead.load_sodium(path)
|
||||||
|
|
||||||
if aead.sodium_loaded:
|
if aead.sodium_loaded:
|
||||||
libsodium = aead.libsodium
|
libsodium = aead.libsodium
|
||||||
else:
|
else:
|
||||||
print('load libsodium again')
|
print('load libsodium again with path %s' % path)
|
||||||
libsodium = util.find_library('sodium', 'crypto_stream_salsa20_xor_ic',
|
libsodium = util.find_library('sodium', 'crypto_stream_salsa20_xor_ic',
|
||||||
'libsodium')
|
'libsodium', path)
|
||||||
if libsodium is None:
|
if libsodium is None:
|
||||||
raise Exception('libsodium not found')
|
raise Exception('libsodium not found')
|
||||||
|
|
||||||
|
@ -55,22 +58,35 @@ def load_libsodium():
|
||||||
raise Exception('libsodium init failed')
|
raise Exception('libsodium init failed')
|
||||||
|
|
||||||
libsodium.crypto_stream_salsa20_xor_ic.restype = c_int
|
libsodium.crypto_stream_salsa20_xor_ic.restype = c_int
|
||||||
libsodium.crypto_stream_salsa20_xor_ic.argtypes = (c_void_p, c_char_p,
|
libsodium.crypto_stream_salsa20_xor_ic.argtypes = (
|
||||||
c_ulonglong,
|
c_void_p, c_char_p, # cipher output, msg
|
||||||
c_char_p, c_ulonglong,
|
c_ulonglong, # msg len
|
||||||
c_char_p)
|
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.restype = c_int
|
||||||
libsodium.crypto_stream_chacha20_xor_ic.argtypes = (c_void_p, c_char_p,
|
libsodium.crypto_stream_chacha20_xor_ic.argtypes = (
|
||||||
|
c_void_p, c_char_p,
|
||||||
c_ulonglong,
|
c_ulonglong,
|
||||||
c_char_p, c_ulonglong,
|
c_char_p, c_ulonglong,
|
||||||
c_char_p)
|
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.restype = c_int
|
||||||
libsodium.crypto_stream_chacha20_ietf_xor_ic.argtypes = (c_void_p,
|
libsodium.crypto_stream_chacha20_ietf_xor_ic.argtypes = (
|
||||||
c_char_p,
|
c_void_p, c_char_p,
|
||||||
c_ulonglong,
|
c_ulonglong,
|
||||||
c_char_p,
|
c_char_p,
|
||||||
c_ulong,
|
c_uint, # uint32_t initial counter
|
||||||
c_char_p)
|
c_char_p
|
||||||
|
)
|
||||||
|
|
||||||
# chacha20-poly1305
|
# chacha20-poly1305
|
||||||
libsodium.crypto_aead_chacha20poly1305_encrypt.restype = c_int
|
libsodium.crypto_aead_chacha20poly1305_encrypt.restype = c_int
|
||||||
|
@ -154,9 +170,9 @@ def load_libsodium():
|
||||||
|
|
||||||
|
|
||||||
class SodiumCrypto(object):
|
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:
|
if not loaded:
|
||||||
load_libsodium()
|
load_libsodium(crypto_path)
|
||||||
self.key = key
|
self.key = key
|
||||||
self.iv = iv
|
self.iv = iv
|
||||||
self.key_ptr = c_char_p(key)
|
self.key_ptr = c_char_p(key)
|
||||||
|
@ -165,6 +181,11 @@ class SodiumCrypto(object):
|
||||||
self.cipher = libsodium.crypto_stream_salsa20_xor_ic
|
self.cipher = libsodium.crypto_stream_salsa20_xor_ic
|
||||||
elif cipher_name == 'chacha20':
|
elif cipher_name == 'chacha20':
|
||||||
self.cipher = libsodium.crypto_stream_chacha20_xor_ic
|
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':
|
elif cipher_name == 'chacha20-ietf':
|
||||||
self.cipher = libsodium.crypto_stream_chacha20_ietf_xor_ic
|
self.cipher = libsodium.crypto_stream_chacha20_ietf_xor_ic
|
||||||
else:
|
else:
|
||||||
|
@ -198,10 +219,10 @@ class SodiumCrypto(object):
|
||||||
|
|
||||||
|
|
||||||
class SodiumAeadCrypto(AeadCryptoBase):
|
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:
|
if not loaded:
|
||||||
load_libsodium()
|
load_libsodium(crypto_path)
|
||||||
AeadCryptoBase.__init__(self, cipher_name, key, iv, op)
|
AeadCryptoBase.__init__(self, cipher_name, key, iv, op, crypto_path)
|
||||||
|
|
||||||
if cipher_name == 'chacha20-poly1305':
|
if cipher_name == 'chacha20-poly1305':
|
||||||
self.encryptor = libsodium.crypto_aead_chacha20poly1305_encrypt
|
self.encryptor = libsodium.crypto_aead_chacha20poly1305_encrypt
|
||||||
|
@ -219,11 +240,13 @@ class SodiumAeadCrypto(AeadCryptoBase):
|
||||||
self.decryptor = libsodium. \
|
self.decryptor = libsodium. \
|
||||||
crypto_aead_xchacha20poly1305_ietf_decrypt
|
crypto_aead_xchacha20poly1305_ietf_decrypt
|
||||||
else:
|
else:
|
||||||
raise Exception('Unknown cipher')
|
raise Exception('Unsupported cipher')
|
||||||
elif cipher_name == 'sodium:aes-256-gcm':
|
elif cipher_name == 'sodium:aes-256-gcm':
|
||||||
if hasattr(libsodium, 'crypto_aead_aes256gcm_encrypt'):
|
if hasattr(libsodium, 'crypto_aead_aes256gcm_encrypt'):
|
||||||
self.encryptor = libsodium.crypto_aead_aes256gcm_encrypt
|
self.encryptor = libsodium.crypto_aead_aes256gcm_encrypt
|
||||||
self.decryptor = libsodium.crypto_aead_aes256gcm_decrypt
|
self.decryptor = libsodium.crypto_aead_aes256gcm_decrypt
|
||||||
|
else:
|
||||||
|
raise Exception('Unsupported cipher')
|
||||||
else:
|
else:
|
||||||
raise Exception('Unknown cipher')
|
raise Exception('Unknown cipher')
|
||||||
|
|
||||||
|
@ -269,7 +292,7 @@ class SodiumAeadCrypto(AeadCryptoBase):
|
||||||
raise Exception("Decrypt failed")
|
raise Exception("Decrypt failed")
|
||||||
|
|
||||||
if cipher_out_len.value != clen - self._tlen:
|
if cipher_out_len.value != clen - self._tlen:
|
||||||
raise Exception("Encrypt failed")
|
raise Exception("Decrypt failed")
|
||||||
|
|
||||||
self.cipher_ctx_init()
|
self.cipher_ctx_init()
|
||||||
return buf.raw[:cipher_out_len.value]
|
return buf.raw[:cipher_out_len.value]
|
||||||
|
@ -278,7 +301,9 @@ class SodiumAeadCrypto(AeadCryptoBase):
|
||||||
ciphers = {
|
ciphers = {
|
||||||
'salsa20': (32, 8, SodiumCrypto),
|
'salsa20': (32, 8, SodiumCrypto),
|
||||||
'chacha20': (32, 8, SodiumCrypto),
|
'chacha20': (32, 8, SodiumCrypto),
|
||||||
|
'xchacha20': (32, 24, SodiumCrypto),
|
||||||
'chacha20-ietf': (32, 12, SodiumCrypto),
|
'chacha20-ietf': (32, 12, SodiumCrypto),
|
||||||
|
# AEAD: iv_len = salt_len = key_len
|
||||||
'chacha20-poly1305': (32, 32, SodiumAeadCrypto),
|
'chacha20-poly1305': (32, 32, SodiumAeadCrypto),
|
||||||
'chacha20-ietf-poly1305': (32, 32, SodiumAeadCrypto),
|
'chacha20-ietf-poly1305': (32, 32, SodiumAeadCrypto),
|
||||||
'xchacha20-ietf-poly1305': (32, 32, SodiumAeadCrypto),
|
'xchacha20-ietf-poly1305': (32, 32, SodiumAeadCrypto),
|
||||||
|
@ -286,17 +311,7 @@ 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)
|
|
||||||
|
|
||||||
util.run_cipher(cipher, decipher)
|
|
||||||
|
|
||||||
|
|
||||||
def test_chacha20():
|
def test_chacha20():
|
||||||
|
|
||||||
print("Test chacha20")
|
print("Test chacha20")
|
||||||
cipher = SodiumCrypto('chacha20', b'k' * 32, b'i' * 16, 1)
|
cipher = SodiumCrypto('chacha20', b'k' * 32, b'i' * 16, 1)
|
||||||
decipher = SodiumCrypto('chacha20', b'k' * 32, b'i' * 16, 0)
|
decipher = SodiumCrypto('chacha20', b'k' * 32, b'i' * 16, 0)
|
||||||
|
@ -304,8 +319,23 @@ def test_chacha20():
|
||||||
util.run_cipher(cipher, decipher)
|
util.run_cipher(cipher, decipher)
|
||||||
|
|
||||||
|
|
||||||
def test_chacha20_ietf():
|
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)
|
||||||
|
|
||||||
|
|
||||||
|
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")
|
print("Test chacha20-ietf")
|
||||||
cipher = SodiumCrypto('chacha20-ietf', b'k' * 32, b'i' * 16, 1)
|
cipher = SodiumCrypto('chacha20-ietf', b'k' * 32, b'i' * 16, 1)
|
||||||
decipher = SodiumCrypto('chacha20-ietf', b'k' * 32, b'i' * 16, 0)
|
decipher = SodiumCrypto('chacha20-ietf', b'k' * 32, b'i' * 16, 0)
|
||||||
|
@ -314,7 +344,6 @@ def test_chacha20_ietf():
|
||||||
|
|
||||||
|
|
||||||
def test_chacha20_poly1305():
|
def test_chacha20_poly1305():
|
||||||
|
|
||||||
print("Test chacha20-poly1305 [payload][tag]")
|
print("Test chacha20-poly1305 [payload][tag]")
|
||||||
cipher = SodiumAeadCrypto('chacha20-poly1305',
|
cipher = SodiumAeadCrypto('chacha20-poly1305',
|
||||||
b'k' * 32, b'i' * 32, 1)
|
b'k' * 32, b'i' * 32, 1)
|
||||||
|
@ -325,7 +354,6 @@ def test_chacha20_poly1305():
|
||||||
|
|
||||||
|
|
||||||
def test_chacha20_poly1305_chunk():
|
def test_chacha20_poly1305_chunk():
|
||||||
|
|
||||||
print("Test chacha20-poly1305 chunk [size][tag][payload][tag]")
|
print("Test chacha20-poly1305 chunk [size][tag][payload][tag]")
|
||||||
cipher = SodiumAeadCrypto('chacha20-poly1305',
|
cipher = SodiumAeadCrypto('chacha20-poly1305',
|
||||||
b'k' * 32, b'i' * 32, 1)
|
b'k' * 32, b'i' * 32, 1)
|
||||||
|
@ -339,7 +367,6 @@ def test_chacha20_poly1305_chunk():
|
||||||
|
|
||||||
|
|
||||||
def test_chacha20_ietf_poly1305():
|
def test_chacha20_ietf_poly1305():
|
||||||
|
|
||||||
print("Test chacha20-ietf-poly1305 [payload][tag]")
|
print("Test chacha20-ietf-poly1305 [payload][tag]")
|
||||||
cipher = SodiumAeadCrypto('chacha20-ietf-poly1305',
|
cipher = SodiumAeadCrypto('chacha20-ietf-poly1305',
|
||||||
b'k' * 32, b'i' * 32, 1)
|
b'k' * 32, b'i' * 32, 1)
|
||||||
|
@ -350,7 +377,6 @@ def test_chacha20_ietf_poly1305():
|
||||||
|
|
||||||
|
|
||||||
def test_chacha20_ietf_poly1305_chunk():
|
def test_chacha20_ietf_poly1305_chunk():
|
||||||
|
|
||||||
print("Test chacha20-ietf-poly1305 chunk [size][tag][payload][tag]")
|
print("Test chacha20-ietf-poly1305 chunk [size][tag][payload][tag]")
|
||||||
cipher = SodiumAeadCrypto('chacha20-ietf-poly1305',
|
cipher = SodiumAeadCrypto('chacha20-ietf-poly1305',
|
||||||
b'k' * 32, b'i' * 32, 1)
|
b'k' * 32, b'i' * 32, 1)
|
||||||
|
@ -364,7 +390,6 @@ def test_chacha20_ietf_poly1305_chunk():
|
||||||
|
|
||||||
|
|
||||||
def test_aes_256_gcm():
|
def test_aes_256_gcm():
|
||||||
|
|
||||||
print("Test sodium:aes-256-gcm [payload][tag]")
|
print("Test sodium:aes-256-gcm [payload][tag]")
|
||||||
cipher = SodiumAeadCrypto('sodium:aes-256-gcm',
|
cipher = SodiumAeadCrypto('sodium:aes-256-gcm',
|
||||||
b'k' * 32, b'i' * 32, 1)
|
b'k' * 32, b'i' * 32, 1)
|
||||||
|
@ -375,7 +400,6 @@ def test_aes_256_gcm():
|
||||||
|
|
||||||
|
|
||||||
def test_aes_256_gcm_chunk():
|
def test_aes_256_gcm_chunk():
|
||||||
|
|
||||||
print("Test sodium:aes-256-gcm chunk [size][tag][payload][tag]")
|
print("Test sodium:aes-256-gcm chunk [size][tag][payload][tag]")
|
||||||
cipher = SodiumAeadCrypto('sodium:aes-256-gcm',
|
cipher = SodiumAeadCrypto('sodium:aes-256-gcm',
|
||||||
b'k' * 32, b'i' * 32, 1)
|
b'k' * 32, b'i' * 32, 1)
|
||||||
|
@ -390,6 +414,7 @@ def test_aes_256_gcm_chunk():
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
test_chacha20()
|
test_chacha20()
|
||||||
|
test_xchacha20()
|
||||||
test_salsa20()
|
test_salsa20()
|
||||||
test_chacha20_ietf()
|
test_chacha20_ietf()
|
||||||
test_chacha20_poly1305()
|
test_chacha20_poly1305()
|
||||||
|
|
|
@ -55,7 +55,7 @@ def init_table(key):
|
||||||
|
|
||||||
|
|
||||||
class TableCipher(object):
|
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._encrypt_table, self._decrypt_table = init_table(key)
|
||||||
self._op = op
|
self._op = op
|
||||||
self.encrypt = self.update
|
self.encrypt = self.update
|
||||||
|
|
|
@ -41,9 +41,27 @@ def find_library_nt(name):
|
||||||
return results
|
return results
|
||||||
|
|
||||||
|
|
||||||
def find_library(possible_lib_names, search_symbol, library_name):
|
def load_library(path, search_symbol, library_name):
|
||||||
import ctypes.util
|
|
||||||
from ctypes import CDLL
|
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 = []
|
paths = []
|
||||||
|
|
||||||
|
@ -81,16 +99,9 @@ def find_library(possible_lib_names, search_symbol, library_name):
|
||||||
if files:
|
if files:
|
||||||
paths.extend(files)
|
paths.extend(files)
|
||||||
for path in paths:
|
for path in paths:
|
||||||
try:
|
lib = load_library(path, search_symbol, library_name)
|
||||||
lib = CDLL(path)
|
if lib:
|
||||||
if hasattr(lib, search_symbol):
|
|
||||||
logging.info('loading %s from %s', library_name, path)
|
|
||||||
return lib
|
return lib
|
||||||
else:
|
|
||||||
logging.warn('can\'t find symbol %s in %s', search_symbol,
|
|
||||||
path)
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ import hashlib
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from shadowsocks import common
|
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
|
CIPHER_ENC_ENCRYPTION = 1
|
||||||
|
@ -36,6 +36,7 @@ METHOD_INFO_CRYPTO = 2
|
||||||
method_supported = {}
|
method_supported = {}
|
||||||
method_supported.update(rc4_md5.ciphers)
|
method_supported.update(rc4_md5.ciphers)
|
||||||
method_supported.update(openssl.ciphers)
|
method_supported.update(openssl.ciphers)
|
||||||
|
method_supported.update(mbedtls.ciphers)
|
||||||
method_supported.update(sodium.ciphers)
|
method_supported.update(sodium.ciphers)
|
||||||
method_supported.update(table.ciphers)
|
method_supported.update(table.ciphers)
|
||||||
|
|
||||||
|
@ -46,8 +47,8 @@ def random_string(length):
|
||||||
cached_keys = {}
|
cached_keys = {}
|
||||||
|
|
||||||
|
|
||||||
def try_cipher(key, method=None):
|
def try_cipher(key, method=None, crypto_path=None):
|
||||||
Cryptor(key, method)
|
Cryptor(key, method, crypto_path)
|
||||||
|
|
||||||
|
|
||||||
def EVP_BytesToKey(password, key_len, iv_len):
|
def EVP_BytesToKey(password, key_len, iv_len):
|
||||||
|
@ -75,7 +76,14 @@ def EVP_BytesToKey(password, key_len, iv_len):
|
||||||
|
|
||||||
|
|
||||||
class Cryptor(object):
|
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.password = password
|
||||||
self.key = None
|
self.key = None
|
||||||
self.method = method
|
self.method = method
|
||||||
|
@ -83,6 +91,7 @@ class Cryptor(object):
|
||||||
self.cipher_iv = b''
|
self.cipher_iv = b''
|
||||||
self.decipher = None
|
self.decipher = None
|
||||||
self.decipher_iv = None
|
self.decipher_iv = None
|
||||||
|
self.crypto_path = crypto_path
|
||||||
method = method.lower()
|
method = method.lower()
|
||||||
self._method_info = Cryptor.get_method_info(method)
|
self._method_info = Cryptor.get_method_info(method)
|
||||||
if self._method_info:
|
if self._method_info:
|
||||||
|
@ -118,7 +127,7 @@ class Cryptor(object):
|
||||||
if op == CIPHER_ENC_ENCRYPTION:
|
if op == CIPHER_ENC_ENCRYPTION:
|
||||||
# this iv is for cipher not decipher
|
# this iv is for cipher not decipher
|
||||||
self.cipher_iv = iv
|
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):
|
def encrypt(self, buf):
|
||||||
if len(buf) == 0:
|
if len(buf) == 0:
|
||||||
|
@ -139,7 +148,7 @@ class Cryptor(object):
|
||||||
self.decipher = self.get_cipher(
|
self.decipher = self.get_cipher(
|
||||||
self.password, self.method,
|
self.password, self.method,
|
||||||
CIPHER_ENC_DECRYPTION,
|
CIPHER_ENC_DECRYPTION,
|
||||||
iv=decipher_iv
|
decipher_iv
|
||||||
)
|
)
|
||||||
buf = buf[decipher_iv_len:]
|
buf = buf[decipher_iv_len:]
|
||||||
if len(buf) == 0:
|
if len(buf) == 0:
|
||||||
|
@ -158,30 +167,30 @@ def gen_key_iv(password, method):
|
||||||
return key, iv, m
|
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]
|
result = [iv]
|
||||||
cipher = m(method, key, iv, 1)
|
cipher = m(method, key, iv, 1, crypto_path)
|
||||||
result.append(cipher.encrypt_once(data))
|
result.append(cipher.encrypt_once(data))
|
||||||
return b''.join(result)
|
return b''.join(result)
|
||||||
|
|
||||||
|
|
||||||
def decrypt_all(password, method, data):
|
def decrypt_all(password, method, data, crypto_path=None):
|
||||||
result = []
|
result = []
|
||||||
method = method.lower()
|
method = method.lower()
|
||||||
(key, iv, m) = gen_key_iv(password, method)
|
(key, iv, m) = gen_key_iv(password, method)
|
||||||
iv = data[:len(iv)]
|
iv = data[:len(iv)]
|
||||||
data = 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))
|
result.append(cipher.decrypt_once(data))
|
||||||
return b''.join(result), key, iv
|
return b''.join(result), key, iv
|
||||||
|
|
||||||
|
|
||||||
def encrypt_all(password, method, data):
|
def encrypt_all(password, method, data, crypto_path=None):
|
||||||
result = []
|
result = []
|
||||||
method = method.lower()
|
method = method.lower()
|
||||||
(key, iv, m) = gen_key_iv(password, method)
|
(key, iv, m) = gen_key_iv(password, method)
|
||||||
result.append(iv)
|
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))
|
result.append(cipher.encrypt_once(data))
|
||||||
return b''.join(result)
|
return b''.join(result)
|
||||||
|
|
||||||
|
@ -189,6 +198,7 @@ def encrypt_all(password, method, data):
|
||||||
CIPHERS_TO_TEST = [
|
CIPHERS_TO_TEST = [
|
||||||
'aes-128-cfb',
|
'aes-128-cfb',
|
||||||
'aes-256-cfb',
|
'aes-256-cfb',
|
||||||
|
'aes-256-gcm',
|
||||||
'rc4-md5',
|
'rc4-md5',
|
||||||
'salsa20',
|
'salsa20',
|
||||||
'chacha20',
|
'chacha20',
|
||||||
|
|
|
@ -71,6 +71,7 @@ class Manager(object):
|
||||||
|
|
||||||
port_password = config['port_password']
|
port_password = config['port_password']
|
||||||
del config['port_password']
|
del config['port_password']
|
||||||
|
config['crypto_path'] = config.get('crypto_path', dict())
|
||||||
for port, password in port_password.items():
|
for port, password in port_password.items():
|
||||||
a_config = config.copy()
|
a_config = config.copy()
|
||||||
a_config['server_port'] = int(port)
|
a_config['server_port'] = int(port)
|
||||||
|
|
|
@ -201,7 +201,12 @@ def check_config(config, is_local):
|
||||||
config['dns_server'] = to_str(config['dns_server'])
|
config['dns_server'] = to_str(config['dns_server'])
|
||||||
logging.info('Specified DNS server: %s' % 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):
|
def get_config(is_local):
|
||||||
|
@ -212,12 +217,12 @@ def get_config(is_local):
|
||||||
if is_local:
|
if is_local:
|
||||||
shortopts = 'hd:s:b:p:k:l:m:c:t:vqa'
|
shortopts = 'hd:s:b:p:k:l:m:c:t:vqa'
|
||||||
longopts = ['help', 'fast-open', 'pid-file=', 'log-file=', 'user=',
|
longopts = ['help', 'fast-open', 'pid-file=', 'log-file=', 'user=',
|
||||||
'version']
|
'libopenssl=', 'libmbedtls=', 'libsodium=', 'version']
|
||||||
else:
|
else:
|
||||||
shortopts = 'hd:s:p:k:m:c:t:vqa'
|
shortopts = 'hd:s:p:k:m:c:t:vqa'
|
||||||
longopts = ['help', 'fast-open', 'pid-file=', 'log-file=', 'workers=',
|
longopts = ['help', 'fast-open', 'pid-file=', 'log-file=', 'workers=',
|
||||||
'forbidden-ip=', 'user=', 'manager-address=', 'version',
|
'forbidden-ip=', 'user=', 'manager-address=', 'version',
|
||||||
'prefer-ipv6']
|
'libopenssl=', 'libmbedtls=', 'libsodium=', 'prefer-ipv6']
|
||||||
try:
|
try:
|
||||||
config_path = find_config()
|
config_path = find_config()
|
||||||
optlist, args = getopt.getopt(sys.argv[1:], shortopts, longopts)
|
optlist, args = getopt.getopt(sys.argv[1:], shortopts, longopts)
|
||||||
|
@ -261,10 +266,16 @@ def get_config(is_local):
|
||||||
config['timeout'] = int(value)
|
config['timeout'] = int(value)
|
||||||
elif key == '--fast-open':
|
elif key == '--fast-open':
|
||||||
config['fast_open'] = True
|
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':
|
elif key == '--workers':
|
||||||
config['workers'] = int(value)
|
config['workers'] = int(value)
|
||||||
elif key == '--manager-address':
|
elif key == '--manager-address':
|
||||||
config['manager_address'] = value
|
config['manager_address'] = to_str(value)
|
||||||
elif key == '--user':
|
elif key == '--user':
|
||||||
config['user'] = to_str(value)
|
config['user'] = to_str(value)
|
||||||
elif key == '--forbidden-ip':
|
elif key == '--forbidden-ip':
|
||||||
|
@ -313,11 +324,14 @@ def get_config(is_local):
|
||||||
config['one_time_auth'] = config.get('one_time_auth', False)
|
config['one_time_auth'] = config.get('one_time_auth', False)
|
||||||
config['prefer_ipv6'] = config.get('prefer_ipv6', False)
|
config['prefer_ipv6'] = config.get('prefer_ipv6', False)
|
||||||
config['server_port'] = config.get('server_port', 8388)
|
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'] = to_str(config.get('tunnel_remote', '8.8.8.8'))
|
||||||
config['tunnel_remote_port'] = config.get('tunnel_remote_port', 53)
|
config['tunnel_remote_port'] = config.get('tunnel_remote_port', 53)
|
||||||
config['tunnel_port'] = config.get('tunnel_port', 53)
|
config['tunnel_port'] = config.get('tunnel_port', 53)
|
||||||
config['dns_server'] = config.get('dns_server', None)
|
|
||||||
|
|
||||||
logging.getLogger('').handlers = []
|
logging.getLogger('').handlers = []
|
||||||
logging.addLevelName(VERBOSE_LEVEL, 'VERBOSE')
|
logging.addLevelName(VERBOSE_LEVEL, 'VERBOSE')
|
||||||
|
@ -364,29 +378,38 @@ Proxy options:
|
||||||
-m METHOD encryption method, default: aes-256-cfb
|
-m METHOD encryption method, default: aes-256-cfb
|
||||||
Sodium:
|
Sodium:
|
||||||
chacha20-poly1305, chacha20-ietf-poly1305,
|
chacha20-poly1305, chacha20-ietf-poly1305,
|
||||||
*xchacha20-ietf-poly1305,
|
xchacha20-ietf-poly1305,
|
||||||
sodium:aes-256-gcm,
|
sodium:aes-256-gcm,
|
||||||
salsa20, chacha20, chacha20-ietf.
|
salsa20, chacha20, chacha20-ietf.
|
||||||
OpenSSL:(* v1.1)
|
Sodium 1.0.12:
|
||||||
*aes-128-ocb, *aes-192-ocb, *aes-256-ocb,
|
xchacha20
|
||||||
aes-128-gcm, aes-192-gcm, aes-256-gcm,
|
OpenSSL:
|
||||||
aes-128-cfb, aes-192-cfb, aes-256-cfb,
|
aes-{128|192|256}-gcm, aes-{128|192|256}-cfb,
|
||||||
aes-128-ctr, aes-192-ctr, aes-256-ctr,
|
aes-{128|192|256}-ofb, aes-{128|192|256}-ctr,
|
||||||
camellia-128-cfb, camellia-192-cfb,
|
camellia-{128|192|256}-cfb,
|
||||||
camellia-256-cfb,
|
|
||||||
bf-cfb, cast5-cfb, des-cfb, idea-cfb,
|
bf-cfb, cast5-cfb, des-cfb, idea-cfb,
|
||||||
rc2-cfb, seed-cfb,
|
rc2-cfb, seed-cfb,
|
||||||
rc4, rc4-md5, table.
|
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
|
-t TIMEOUT timeout in seconds, default: 300
|
||||||
-a ONE_TIME_AUTH one time auth
|
-a ONE_TIME_AUTH one time auth
|
||||||
--fast-open use TCP_FASTOPEN, requires Linux 3.7+
|
--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:
|
General options:
|
||||||
-h, --help show this help message and exit
|
-h, --help show this help message and exit
|
||||||
-d start/stop/restart daemon mode
|
-d start/stop/restart daemon mode
|
||||||
--pid-file PID_FILE pid file for daemon mode
|
--pid-file=PID_FILE pid file for daemon mode
|
||||||
--log-file LOG_FILE log file for daemon mode
|
--log-file=LOG_FILE log file for daemon mode
|
||||||
--user USER username to run as
|
--user=USER username to run as
|
||||||
-v, -vv verbose mode
|
-v, -vv verbose mode
|
||||||
-q, -qq quiet mode, only show warnings/errors
|
-q, -qq quiet mode, only show warnings/errors
|
||||||
--version show version information
|
--version show version information
|
||||||
|
@ -409,26 +432,35 @@ Proxy options:
|
||||||
-m METHOD encryption method, default: aes-256-cfb
|
-m METHOD encryption method, default: aes-256-cfb
|
||||||
Sodium:
|
Sodium:
|
||||||
chacha20-poly1305, chacha20-ietf-poly1305,
|
chacha20-poly1305, chacha20-ietf-poly1305,
|
||||||
*xchacha20-ietf-poly1305,
|
xchacha20-ietf-poly1305,
|
||||||
sodium:aes-256-gcm,
|
sodium:aes-256-gcm,
|
||||||
salsa20, chacha20, chacha20-ietf.
|
salsa20, chacha20, chacha20-ietf.
|
||||||
OpenSSL:(* v1.1)
|
Sodium 1.0.12:
|
||||||
*aes-128-ocb, *aes-192-ocb, *aes-256-ocb,
|
xchacha20
|
||||||
aes-128-gcm, aes-192-gcm, aes-256-gcm,
|
OpenSSL:
|
||||||
aes-128-cfb, aes-192-cfb, aes-256-cfb,
|
aes-{128|192|256}-gcm, aes-{128|192|256}-cfb,
|
||||||
aes-128-ctr, aes-192-ctr, aes-256-ctr,
|
aes-{128|192|256}-ofb, aes-{128|192|256}-ctr,
|
||||||
camellia-128-cfb, camellia-192-cfb,
|
camellia-{128|192|256}-cfb,
|
||||||
camellia-256-cfb,
|
|
||||||
bf-cfb, cast5-cfb, des-cfb, idea-cfb,
|
bf-cfb, cast5-cfb, des-cfb, idea-cfb,
|
||||||
rc2-cfb, seed-cfb,
|
rc2-cfb, seed-cfb,
|
||||||
rc4, rc4-md5, table.
|
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
|
-t TIMEOUT timeout in seconds, default: 300
|
||||||
-a ONE_TIME_AUTH one time auth
|
-a ONE_TIME_AUTH one time auth
|
||||||
--fast-open use TCP_FASTOPEN, requires Linux 3.7+
|
--fast-open use TCP_FASTOPEN, requires Linux 3.7+
|
||||||
--workers WORKERS number of workers, available on Unix/Linux
|
--workers=WORKERS number of workers, available on Unix/Linux
|
||||||
--forbidden-ip IPLIST comma seperated IP list forbidden to connect
|
--forbidden-ip=IPLIST comma seperated IP list forbidden to connect
|
||||||
--manager-address ADDR optional server manager UDP address, see wiki
|
--manager-address=ADDR optional server manager UDP address, see wiki
|
||||||
--prefer-ipv6 resolve ipv6 address first
|
--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:
|
General options:
|
||||||
-h, --help show this help message and exit
|
-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
|
WAIT_STATUS_READWRITING = WAIT_STATUS_READING | WAIT_STATUS_WRITING
|
||||||
|
|
||||||
BUF_SIZE = 32 * 1024
|
BUF_SIZE = 32 * 1024
|
||||||
|
UP_STREAM_BUF_SIZE = 16 * 1024
|
||||||
|
DOWN_STREAM_BUF_SIZE = 32 * 1024
|
||||||
|
|
||||||
# helper exceptions for TCPRelayHandler
|
# helper exceptions for TCPRelayHandler
|
||||||
|
|
||||||
|
@ -126,7 +128,8 @@ class TCPRelayHandler(object):
|
||||||
self._is_local = is_local
|
self._is_local = is_local
|
||||||
self._stage = STAGE_INIT
|
self._stage = STAGE_INIT
|
||||||
self._cryptor = cryptor.Cryptor(config['password'],
|
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 = config.get('one_time_auth', False)
|
||||||
self._ota_enable_session = self._ota_enable
|
self._ota_enable_session = self._ota_enable
|
||||||
self._ota_buff_head = b''
|
self._ota_buff_head = b''
|
||||||
|
@ -553,8 +556,12 @@ class TCPRelayHandler(object):
|
||||||
return
|
return
|
||||||
is_local = self._is_local
|
is_local = self._is_local
|
||||||
data = None
|
data = None
|
||||||
|
if is_local:
|
||||||
|
buf_size = UP_STREAM_BUF_SIZE
|
||||||
|
else:
|
||||||
|
buf_size = DOWN_STREAM_BUF_SIZE
|
||||||
try:
|
try:
|
||||||
data = self._local_sock.recv(BUF_SIZE)
|
data = self._local_sock.recv(buf_size)
|
||||||
except (OSError, IOError) as e:
|
except (OSError, IOError) as e:
|
||||||
if eventloop.errno_from_exception(e) in \
|
if eventloop.errno_from_exception(e) in \
|
||||||
(errno.ETIMEDOUT, errno.EAGAIN, errno.EWOULDBLOCK):
|
(errno.ETIMEDOUT, errno.EAGAIN, errno.EWOULDBLOCK):
|
||||||
|
@ -586,8 +593,12 @@ class TCPRelayHandler(object):
|
||||||
def _on_remote_read(self):
|
def _on_remote_read(self):
|
||||||
# handle all remote read events
|
# handle all remote read events
|
||||||
data = None
|
data = None
|
||||||
|
if self._is_local:
|
||||||
|
buf_size = UP_STREAM_BUF_SIZE
|
||||||
|
else:
|
||||||
|
buf_size = DOWN_STREAM_BUF_SIZE
|
||||||
try:
|
try:
|
||||||
data = self._remote_sock.recv(BUF_SIZE)
|
data = self._remote_sock.recv(buf_size)
|
||||||
|
|
||||||
except (OSError, IOError) as e:
|
except (OSError, IOError) as e:
|
||||||
if eventloop.errno_from_exception(e) in \
|
if eventloop.errno_from_exception(e) in \
|
||||||
|
|
|
@ -115,6 +115,8 @@ class UDPRelay(object):
|
||||||
self._closed = False
|
self._closed = False
|
||||||
self._sockets = set()
|
self._sockets = set()
|
||||||
self._forbidden_iplist = config.get('forbidden_ip')
|
self._forbidden_iplist = config.get('forbidden_ip')
|
||||||
|
self._crypto_path = config['crypto_path']
|
||||||
|
|
||||||
addrs = socket.getaddrinfo(self._listen_addr, self._listen_port, 0,
|
addrs = socket.getaddrinfo(self._listen_addr, self._listen_port, 0,
|
||||||
socket.SOCK_DGRAM, socket.SOL_UDP)
|
socket.SOCK_DGRAM, socket.SOL_UDP)
|
||||||
if len(addrs) == 0:
|
if len(addrs) == 0:
|
||||||
|
@ -174,7 +176,7 @@ class UDPRelay(object):
|
||||||
try:
|
try:
|
||||||
data, key, iv = cryptor.decrypt_all(self._password,
|
data, key, iv = cryptor.decrypt_all(self._password,
|
||||||
self._method,
|
self._method,
|
||||||
data)
|
data, self._crypto_path)
|
||||||
except Exception:
|
except Exception:
|
||||||
logging.debug('UDP handle_server: decrypt data failed')
|
logging.debug('UDP handle_server: decrypt data failed')
|
||||||
return
|
return
|
||||||
|
@ -241,7 +243,8 @@ class UDPRelay(object):
|
||||||
if self._ota_enable_session:
|
if self._ota_enable_session:
|
||||||
data = self._ota_chunk_data_gen(key, iv, data)
|
data = self._ota_chunk_data_gen(key, iv, data)
|
||||||
try:
|
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:
|
except Exception:
|
||||||
logging.debug("UDP handle_server: encrypt data failed")
|
logging.debug("UDP handle_server: encrypt data failed")
|
||||||
return
|
return
|
||||||
|
@ -275,7 +278,8 @@ class UDPRelay(object):
|
||||||
data = pack_addr(r_addr[0]) + struct.pack('>H', r_addr[1]) + data
|
data = pack_addr(r_addr[0]) + struct.pack('>H', r_addr[1]) + data
|
||||||
try:
|
try:
|
||||||
response = cryptor.encrypt_all(self._password,
|
response = cryptor.encrypt_all(self._password,
|
||||||
self._method, data)
|
self._method, data,
|
||||||
|
self._crypto_path)
|
||||||
except Exception:
|
except Exception:
|
||||||
logging.debug("UDP handle_client: encrypt data failed")
|
logging.debug("UDP handle_client: encrypt data failed")
|
||||||
return
|
return
|
||||||
|
@ -284,7 +288,8 @@ class UDPRelay(object):
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
data, key, iv = cryptor.decrypt_all(self._password,
|
data, key, iv = cryptor.decrypt_all(self._password,
|
||||||
self._method, data)
|
self._method, data,
|
||||||
|
self._crypto_path)
|
||||||
except Exception:
|
except Exception:
|
||||||
logging.debug('UDP handle_client: decrypt data failed')
|
logging.debug('UDP handle_client: decrypt data failed')
|
||||||
return
|
return
|
||||||
|
|
10
tests/aes-gcm.json
Normal file
10
tests/aes-gcm.json
Normal file
|
@ -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
|
||||||
|
}
|
11
tests/aes-ocb.json
Normal file
11
tests/aes-ocb.json
Normal file
|
@ -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"
|
||||||
|
}
|
10
tests/aes-ofb.json
Normal file
10
tests/aes-ofb.json
Normal file
|
@ -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
|
||||||
|
}
|
10
tests/camellia.json
Normal file
10
tests/camellia.json
Normal file
|
@ -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
|
||||||
|
}
|
10
tests/chacha20-ietf-poly1305.json
Normal file
10
tests/chacha20-ietf-poly1305.json
Normal file
|
@ -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
|
||||||
|
}
|
10
tests/chacha20-poly1305.json
Normal file
10
tests/chacha20-poly1305.json
Normal file
|
@ -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
|
||||||
|
}
|
|
@ -2,7 +2,7 @@
|
||||||
"server":"127.0.0.1",
|
"server":"127.0.0.1",
|
||||||
"server_port":8388,
|
"server_port":8388,
|
||||||
"local_port":1081,
|
"local_port":1081,
|
||||||
"password":"salsa20_password",
|
"password":"chacha20_password",
|
||||||
"timeout":60,
|
"timeout":60,
|
||||||
"method":"chacha20",
|
"method":"chacha20",
|
||||||
"local_address":"127.0.0.1",
|
"local_address":"127.0.0.1",
|
||||||
|
|
|
@ -33,12 +33,25 @@ run_test coverage run tests/nose_plugin.py -v
|
||||||
run_test python setup.py sdist
|
run_test python setup.py sdist
|
||||||
run_test tests/test_daemon.sh
|
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/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/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-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-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/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/salsa20.json
|
||||||
run_test python tests/test.py --with-coverage -c tests/chacha20.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/table.json
|
||||||
run_test python tests/test.py --with-coverage -c tests/server-multi-ports.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
|
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 -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"
|
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
|
# test if DNS works
|
||||||
run_test python tests/test.py --with-coverage -c tests/aes.json --url="https://clients1.google.com/generate_204"
|
run_test python tests/test.py --with-coverage -c tests/aes.json --url="https://clients1.google.com/generate_204"
|
||||||
|
|
||||||
|
|
12
tests/libmbedtls/install.sh
Executable file
12
tests/libmbedtls/install.sh
Executable file
|
@ -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
|
12
tests/libopenssl/install.sh
Executable file
12
tests/libopenssl/install.sh
Executable file
|
@ -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
|
#!/bin/bash
|
||||||
|
|
||||||
if [ ! -d libsodium-1.0.11 ]; then
|
if [ ! -d libsodium-1.0.12 ]; then
|
||||||
wget https://github.com/jedisct1/libsodium/releases/download/1.0.11/libsodium-1.0.11.tar.gz || exit 1
|
wget https://github.com/jedisct1/libsodium/releases/download/1.0.12/libsodium-1.0.12.tar.gz || exit 1
|
||||||
tar xf libsodium-1.0.11.tar.gz || exit 1
|
tar xf libsodium-1.0.12.tar.gz || exit 1
|
||||||
fi
|
fi
|
||||||
pushd libsodium-1.0.11
|
pushd libsodium-1.0.12
|
||||||
./configure && make -j2 && make install || exit 1
|
./configure && make -j2 && make install || exit 1
|
||||||
sudo ldconfig
|
sudo ldconfig
|
||||||
popd
|
popd
|
||||||
|
rm -rf libsodium-1.0.12 || exit 1
|
||||||
|
|
10
tests/mbedtls-aes-ctr.json
Normal file
10
tests/mbedtls-aes-ctr.json
Normal file
|
@ -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
|
||||||
|
}
|
10
tests/mbedtls-aes-gcm.json
Normal file
10
tests/mbedtls-aes-gcm.json
Normal file
|
@ -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
|
||||||
|
}
|
10
tests/mbedtls-aes.json
Normal file
10
tests/mbedtls-aes.json
Normal file
|
@ -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
|
||||||
|
}
|
10
tests/mbedtls-camellia.json
Normal file
10
tests/mbedtls-camellia.json
Normal file
|
@ -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
|
||||||
|
}
|
10
tests/xchacha20-ietf-poly1305.json
Normal file
10
tests/xchacha20-ietf-poly1305.json
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"server":"127.0.0.1",
|
||||||
|
"server_port":8388,
|
||||||
|
"local_port":1081,
|
||||||
|
"password":"salsa20_password",
|
||||||
|
"timeout":60,
|
||||||
|
"method":"xchacha20-ietf-poly1305",
|
||||||
|
"local_address":"127.0.0.1",
|
||||||
|
"fast_open":false
|
||||||
|
}
|
10
tests/xchacha20.json
Normal file
10
tests/xchacha20.json
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"server":"127.0.0.1",
|
||||||
|
"server_port":8388,
|
||||||
|
"local_port":1081,
|
||||||
|
"password":"xchacha20_password",
|
||||||
|
"timeout":60,
|
||||||
|
"method":"xchacha20",
|
||||||
|
"local_address":"127.0.0.1",
|
||||||
|
"fast_open":false
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue