diff --git a/Makefile.in b/Makefile.in index 216d1947..5647800f 100644 --- a/Makefile.in +++ b/Makefile.in @@ -43,8 +43,8 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/acx_pthread.m4 \ $(top_srcdir)/m4/inet_ntop.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ - $(top_srcdir)/m4/openssl.m4 $(top_srcdir)/libev/libev.m4 \ - $(top_srcdir)/configure.ac + $(top_srcdir)/m4/openssl.m4 $(top_srcdir)/m4/polarssl.m4 \ + $(top_srcdir)/libev/libev.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ diff --git a/README.md b/README.md index ae795032..d26e37b3 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ Features Shadowsocks-libev is writen in pure C and only depends on [libev](http://software.schmorp.de/pkg/libev.html) and -[openssl](http://www.openssl.org/). +[openssl](http://www.openssl.org/) or [polarssl](https://polarssl.org/). In normal usage, the memory consumption is about 600KB and the CPU utilization is no more than 5% on a low-end router (Buffalo WHR-G300N V2 with a 400MHz MIPS CPU, @@ -64,6 +64,10 @@ no more than 5% on a low-end router (Buffalo WHR-G300N V2 with a 400MHz MIPS CPU Installation ------------ +__Note__: Default crypto library is OpenSSL. To build against PolarSSL, +specify `--with-crypto-library=polarssl` and `--with-polarssl=/path/to/polarssl` +when running `./configure`. + ### Linux For Unix-like systems, especially Debian-based systems, @@ -129,9 +133,11 @@ make V=99 package/shadowsocks-libev/openwrt/compile For Windows, use either MinGW (msys) or Cygwin to build. At the moment, only `ss-local` is supported to build against MinGW (msys). -If you are using MinGW (msys), please download OpenSSL source tarball +If you are using MinGW (msys), please download OpenSSL or PolarSSL source tarball to the home directory of msys, and build it like this (may take a few minutes): +* OpenSSL + ```bash tar zxf openssl-1.0.1e.tar.gz cd openssl-1.0.1e @@ -139,14 +145,32 @@ cd openssl-1.0.1e make && make install ``` +* PolarSSL + +```bash +tar zxf polarssl-1.3.2-gpl.tgz +cd polarssl-1.3.2 +make lib WINDOWS=1 +make install DESTDIR="$HOME/prebuilt" +``` + Then, build the binary using the commands below, and all `.exe` files will be built at `$HOME/ss/bin`: +* OpenSSL + ```bash ./configure --prefix="$HOME/ss" --with-openssl="$HOME/prebuilt" make && make install ``` +* PolarSSL + +```bash +./configure --prefix="$HOME/ss" --with-crypto-library=polarssl --with-polarssl=$HOME/prebuilt +make && make install +``` + Usage ----- @@ -156,7 +180,7 @@ usage: ss-[local|redir|server] -s host name or ip address of your remote server -p port number of your remote server - -l > port number of your local server + -l port number of your local server -k password of your remote server [-m ] encrypt method, supporting table, rc4, diff --git a/aclocal.m4 b/aclocal.m4 index 7c0669d3..33cde4f3 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -1073,3 +1073,4 @@ m4_include([m4/ltsugar.m4]) m4_include([m4/ltversion.m4]) m4_include([m4/lt~obsolete.m4]) m4_include([m4/openssl.m4]) +m4_include([m4/polarssl.m4]) diff --git a/config.h.in b/config.h.in index 11de8db0..5dde41b3 100644 --- a/config.h.in +++ b/config.h.in @@ -273,6 +273,12 @@ /* Define to 1 if you can safely include both and . */ #undef TIME_WITH_SYS_TIME +/* Use OpenSSL library */ +#undef USE_CRYPTO_OPENSSL + +/* Use PolarSSL library */ +#undef USE_CRYPTO_POLARSSL + /* Version number of package */ #undef VERSION diff --git a/configure b/configure index 944322ff..e048b227 100755 --- a/configure +++ b/configure @@ -738,6 +738,7 @@ ac_subst_files='' ac_user_opts=' enable_option_checking enable_dependency_tracking +with_crypto_library enable_shared enable_static with_pic @@ -748,6 +749,9 @@ enable_libtool_lock with_openssl with_openssl_include with_openssl_lib +with_polarssl +with_polarssl_include +with_polarssl_lib enable_assert enable_largefile ' @@ -1393,6 +1397,9 @@ Optional Features: Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-crypto-library=library + build with the given crypto library, + TYPE=openssl|polarssl [default=openssl] --with-pic[=PKGS] try to use only PIC/non-PIC objects [default=use both] --with-gnu-ld assume the C compiler uses GNU ld [default=no] @@ -1403,6 +1410,11 @@ Optional Packages: OpenSSL headers directory (without trailing /openssl) --with-openssl-lib=DIR OpenSSL library directory + --with-polarssl=DIR PolarSSL base directory, or: + --with-polarssl-include=DIR + PolarSSL headers directory (without trailing + /polarssl) + --with-polarssl-lib=DIR PolarSSL library directory Some influential environment variables: CC C compiler command @@ -4005,6 +4017,21 @@ unknown) esac + +# Check whether --with-crypto-library was given. +if test "${with_crypto_library+set}" = set; then : + withval=$with_crypto_library; + case "${withval}" in + openssl|polarssl) ;; + *) as_fn_error $? "bad value ${withval} for --with-crypto-library" "$LINENO" 5 ;; + esac + +else + with_crypto_library="openssl" + +fi + + ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -12713,12 +12740,14 @@ fi case $host in *-mingw*) - LIBS="$LIBS -lgdi32 -lws2_32" + LIBS="$LIBS -lgdi32 -lws2_32 -lcrypt32" ;; *) ;; esac +case "${with_crypto_library}" in + openssl) @@ -12836,6 +12865,119 @@ fi +$as_echo "#define USE_CRYPTO_OPENSSL 1" >>confdefs.h + + ;; + polarssl) + + + +# Check whether --with-polarssl was given. +if test "${with_polarssl+set}" = set; then : + withval=$with_polarssl; polarssl="$withval" + CFLAGS="$CFLAGS -I$withval/include" + LDFLAGS="$LDFLAGS -L$withval/lib" + +fi + + + +# Check whether --with-polarssl-include was given. +if test "${with_polarssl_include+set}" = set; then : + withval=$with_polarssl_include; polarssl_include="$withval" + CFLAGS="$CFLAGS -I$withval" + +fi + + + +# Check whether --with-polarssl-lib was given. +if test "${with_polarssl_lib+set}" = set; then : + withval=$with_polarssl_lib; polarssl_lib="$withval" + LDFLAGS="$LDFLAGS -L$withval" + +fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for cipher_init_ctx in -lpolarssl" >&5 +$as_echo_n "checking for cipher_init_ctx in -lpolarssl... " >&6; } +if ${ac_cv_lib_polarssl_cipher_init_ctx+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpolarssl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char cipher_init_ctx (); +int +main () +{ +return cipher_init_ctx (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_polarssl_cipher_init_ctx=yes +else + ac_cv_lib_polarssl_cipher_init_ctx=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_polarssl_cipher_init_ctx" >&5 +$as_echo "$ac_cv_lib_polarssl_cipher_init_ctx" >&6; } +if test "x$ac_cv_lib_polarssl_cipher_init_ctx" = xyes; then : + LIBS="-lpolarssl $LIBS" +else + as_fn_error $? "PolarSSL libraries not found." "$LINENO" 5 + +fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking polarssl version" >&5 +$as_echo_n "checking polarssl version... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include + +int +main () +{ + +#if POLARSSL_VERSION_NUMBER < 0x01020500 +#error invalid version +#endif + + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 +$as_echo "ok" >&6; } +else + as_fn_error $? "PolarSSL 1.2.5 or newer required" "$LINENO" 5 + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + +$as_echo "#define USE_CRYPTO_POLARSSL 1" >>confdefs.h + + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C/C++ restrict keyword" >&5 $as_echo_n "checking for C/C++ restrict keyword... " >&6; } if ${ac_cv_c_restrict+:} false; then : diff --git a/configure.ac b/configure.ac index d3a30969..e301f65e 100755 --- a/configure.ac +++ b/configure.ac @@ -9,6 +9,19 @@ AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE([foreign -Wall -Werror]) m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) +dnl Checks for crypto library +AC_ARG_WITH( + [crypto-library], + [AS_HELP_STRING([--with-crypto-library=library], [build with the given crypto library, TYPE=openssl|polarssl @<:@default=openssl@:>@])], + [ + case "${withval}" in + openssl|polarssl) ;; + *) AC_MSG_ERROR([bad value ${withval} for --with-crypto-library]) ;; + esac + ], + [with_crypto_library="openssl"] +) + dnl Checks for programs. AC_PROG_CC AC_PROG_INSTALL @@ -24,14 +37,23 @@ m4_include([libev/libev.m4]) dnl Add library for mingw case $host in *-mingw*) - LIBS="$LIBS -lgdi32 -lws2_32" + LIBS="$LIBS -lgdi32 -lws2_32 -lcrypt32" ;; *) ;; esac -dnl Checks for openssl -ss_OPENSSL +dnl Checks for crypto library +case "${with_crypto_library}" in + openssl) + ss_OPENSSL + AC_DEFINE([USE_CRYPTO_OPENSSL], [1], [Use OpenSSL library]) + ;; + polarssl) + ss_POLARSSL + AC_DEFINE([USE_CRYPTO_POLARSSL], [1], [Use PolarSSL library]) + ;; +esac dnl Checks for inet_ntop ss_FUNC_INET_NTOP diff --git a/libasyncns/Makefile.in b/libasyncns/Makefile.in index 9306747e..3075d8dc 100644 --- a/libasyncns/Makefile.in +++ b/libasyncns/Makefile.in @@ -59,8 +59,8 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/acx_pthread.m4 \ $(top_srcdir)/m4/inet_ntop.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ - $(top_srcdir)/m4/openssl.m4 $(top_srcdir)/libev/libev.m4 \ - $(top_srcdir)/configure.ac + $(top_srcdir)/m4/openssl.m4 $(top_srcdir)/m4/polarssl.m4 \ + $(top_srcdir)/libev/libev.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d diff --git a/libev/Makefile.in b/libev/Makefile.in index e8f3e655..18ec00ec 100644 --- a/libev/Makefile.in +++ b/libev/Makefile.in @@ -43,8 +43,8 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/acx_pthread.m4 \ $(top_srcdir)/m4/inet_ntop.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ - $(top_srcdir)/m4/openssl.m4 $(top_srcdir)/libev/libev.m4 \ - $(top_srcdir)/configure.ac + $(top_srcdir)/m4/openssl.m4 $(top_srcdir)/m4/polarssl.m4 \ + $(top_srcdir)/libev/libev.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d diff --git a/m4/polarssl.m4 b/m4/polarssl.m4 new file mode 100644 index 00000000..6507efb6 --- /dev/null +++ b/m4/polarssl.m4 @@ -0,0 +1,45 @@ +dnl Check to find the PolarSSL headers/libraries + +AC_DEFUN([ss_POLARSSL], +[ + + AC_ARG_WITH(polarssl, + AS_HELP_STRING([--with-polarssl=DIR], [PolarSSL base directory, or:]), + [polarssl="$withval" + CFLAGS="$CFLAGS -I$withval/include" + LDFLAGS="$LDFLAGS -L$withval/lib"] + ) + + AC_ARG_WITH(polarssl-include, + AS_HELP_STRING([--with-polarssl-include=DIR], [PolarSSL headers directory (without trailing /polarssl)]), + [polarssl_include="$withval" + CFLAGS="$CFLAGS -I$withval"] + ) + + AC_ARG_WITH(polarssl-lib, + AS_HELP_STRING([--with-polarssl-lib=DIR], [PolarSSL library directory]), + [polarssl_lib="$withval" + LDFLAGS="$LDFLAGS -L$withval"] + ) + + AC_CHECK_LIB(polarssl, cipher_init_ctx, + [LIBS="-lpolarssl $LIBS"], + [AC_MSG_ERROR([PolarSSL libraries not found.])] + ) + + AC_MSG_CHECKING([polarssl version]) + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[ +#include + ]], + [[ +#if POLARSSL_VERSION_NUMBER < 0x01020500 +#error invalid version +#endif + ]] + )], + [AC_MSG_RESULT([ok])], + [AC_MSG_ERROR([PolarSSL 1.2.5 or newer required])] + ) +]) diff --git a/openwrt/Makefile b/openwrt/Makefile index a4923b5d..3123f21c 100644 --- a/openwrt/Makefile +++ b/openwrt/Makefile @@ -7,7 +7,7 @@ PKG_RELEASE=$(PKG_SOURCE_VERSION) PKG_SOURCE_PROTO:=git PKG_SOURCE_URL:=https://github.com/madeye/shadowsocks-libev.git PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) -PKG_SOURCE_VERSION:=eb9d31869e1d7590cd8c2fb1e7d226ac6cf32fad +PKG_SOURCE_VERSION:=71c30b31f34f181c02410612e51e1c03ee4f311f PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz PKG_MAINTAINER:=Max Lv @@ -18,21 +18,41 @@ PKG_BUILD_PARALLEL:=1 include $(INCLUDE_DIR)/package.mk -define Package/shadowsocks-libev +define Package/shadowsocks-libev/Default SECTION:=net CATEGORY:=Network - DEPENDS:=+libopenssl TITLE:=Lightweight Secured Socks5 Proxy + URL:=https://github.com/madeye/shadowsocks-libev +endef + +define Package/shadowsocks-libev + $(call Package/shadowsocks-libev/Default) + TITLE+= (OpenSSL) + VARIANT:=openssl + DEPENDS:=+libopenssl +endef + +define Package/shadowsocks-libev-polarssl + $(call Package/shadowsocks-libev/Default) + TITLE+= (PolarSSL) + VARIANT:=polarssl + DEPENDS:=+libpolarssl endef define Package/shadowsocks-libev/description Shadowsocks-libev is a lightweight secured scoks5 proxy for embedded devices and low end boxes. endef +Package/shadowsocks-libev-polarssl/description=$(Package/shadowsocks-libev/description) + define Package/shadowsocks-libev/conffiles /etc/config/shadowsocks.json endef +ifeq ($(BUILD_VARIANT),polarssl) + CONFIGURE_ARGS += --with-crypto-library=polarssl +endif + define Package/shadowsocks-libev/install $(INSTALL_DIR) $(1)/usr/bin $(1)/etc/init.d $(1)/etc/config $(INSTALL_BIN) $(PKG_BUILD_DIR)/src/ss-local $(1)/usr/bin/ss-local @@ -41,5 +61,7 @@ define Package/shadowsocks-libev/install $(INSTALL_CONF) ./files/shadowsocks.json $(1)/etc/config/shadowsocks.json endef -$(eval $(call BuildPackage,shadowsocks-libev)) +Package/shadowsocks-libev-polarssl/install=$(Package/shadowsocks-libev/install) +$(eval $(call BuildPackage,shadowsocks-libev)) +$(eval $(call BuildPackage,shadowsocks-libev-polarssl)) diff --git a/src/Makefile.in b/src/Makefile.in index a33766bf..55f44c78 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -45,8 +45,8 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/acx_pthread.m4 \ $(top_srcdir)/m4/inet_ntop.m4 $(top_srcdir)/m4/libtool.m4 \ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ - $(top_srcdir)/m4/openssl.m4 $(top_srcdir)/libev/libev.m4 \ - $(top_srcdir)/configure.ac + $(top_srcdir)/m4/openssl.m4 $(top_srcdir)/m4/polarssl.m4 \ + $(top_srcdir)/libev/libev.m4 $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d diff --git a/src/encrypt.c b/src/encrypt.c index 2e7f642e..c11587d6 100644 --- a/src/encrypt.c +++ b/src/encrypt.c @@ -3,9 +3,30 @@ #endif #include + +#if defined(USE_CRYPTO_OPENSSL) + #include #include +#elif defined(USE_CRYPTO_POLARSSL) + +#include +#include +#include +#include +#define CIPHER_UNSUPPORTED "unsupported" + +#endif + +#include +#ifdef _WIN32 +#include +#include +#else +#include +#endif + #include "encrypt.h" #include "utils.h" @@ -13,12 +34,12 @@ static uint8_t *enc_table; static uint8_t *dec_table; -static uint8_t enc_key[EVP_MAX_KEY_LENGTH]; +static uint8_t enc_key[MAX_KEY_LENGTH]; static int enc_key_len; static int enc_iv_len; #ifdef DEBUG -static dump(char *tag, char *text) +static void dump(char *tag, char *text) { int i, len; len = strlen(text); @@ -49,6 +70,26 @@ static const char* supported_ciphers[CIPHER_NUM] = "seed-cfb" }; +#ifdef USE_CRYPTO_POLARSSL +static const char* supported_ciphers_polarssl[CIPHER_NUM] = +{ + "table", + "ARC4-128", + "AES-128-CFB128", + "AES-192-CFB128", + "AES-256-CFB128", + "BLOWFISH-CFB64", + "CAMELLIA-128-CFB128", + "CAMELLIA-192-CFB128", + "CAMELLIA-256-CFB128", + CIPHER_UNSUPPORTED, + CIPHER_UNSUPPORTED, + CIPHER_UNSUPPORTED, + CIPHER_UNSUPPORTED, + CIPHER_UNSUPPORTED +}; +#endif + static int random_compare(const void *_x, const void *_y, uint32_t i, uint64_t a) { uint8_t x = *((uint8_t *) _x); @@ -135,6 +176,20 @@ int enc_get_iv_len() return enc_iv_len; } +unsigned char *enc_md5(const unsigned char *d, size_t n, unsigned char *md) +{ +#if defined(USE_CRYPTO_OPENSSL) + return MD5(d, n, md); +#elif defined(USE_CRYPTO_POLARSSL) + static unsigned char m[16]; + if (md == NULL) { + md = m; + } + md5(d, n, md); + return md; +#endif +} + void enc_table_init(const char *pass) { uint32_t i; @@ -145,7 +200,7 @@ void enc_table_init(const char *pass) enc_table = malloc(256); dec_table = malloc(256); - digest = MD5((const uint8_t *)pass, strlen(pass), NULL); + digest = enc_md5((const uint8_t *)pass, strlen(pass), NULL); for (i = 0; i < 8; i++) { @@ -168,57 +223,339 @@ void enc_table_init(const char *pass) } } -char* ss_encrypt_all(int buf_size, char *plaintext, ssize_t *len, int method) +int cipher_iv_size(const cipher_kt_t *cipher) { - if (method > TABLE) - { - const EVP_CIPHER *cipher = EVP_get_cipherbyname(supported_ciphers[method]); - if (cipher == NULL) - { - LOGE("Cipher %s not found in OpenSSL library", supported_ciphers[method]); - FATAL("Cannot initialize cipher"); +#if defined(USE_CRYPTO_OPENSSL) + return EVP_CIPHER_iv_length (cipher); +#elif defined(USE_CRYPTO_POLARSSL) + if (cipher == NULL) { + return 0; + } + return cipher->iv_size; +#endif +} + +int cipher_key_size (const cipher_kt_t *cipher) +{ +#if defined(USE_CRYPTO_OPENSSL) + return EVP_CIPHER_key_length(cipher); +#elif defined(USE_CRYPTO_POLARSSL) + if (cipher == NULL) { + return 0; + } + /* Override PolarSSL 32 bit default key size with sane 128 bit default */ + if (POLARSSL_CIPHER_ID_BLOWFISH == cipher->base->cipher) { + return 128 / 8; + } + return cipher->key_length / 8; +#endif +} + +int bytes_to_key(const cipher_kt_t *cipher, const digest_type_t *md, const uint8_t *pass, uint8_t *key, uint8_t *iv) +{ + size_t datal; + datal = strlen((const char *) pass); +#if defined(USE_CRYPTO_OPENSSL) + return EVP_BytesToKey(cipher, md, NULL, pass, datal, 1, key, iv); +#elif defined(USE_CRYPTO_POLARSSL) + md_context_t c; + unsigned char md_buf[MAX_MD_SIZE]; + int niv; + int nkey; + int addmd; + unsigned int mds; + unsigned int i; + int rv; + + nkey = cipher_key_size(cipher); + niv = cipher_iv_size(cipher); + rv = nkey; + if (pass == NULL) { + return nkey; + } + + memset(&c, 0, sizeof(md_context_t)); + if (md_init_ctx(&c, md)) { + return 0; + } + addmd = 0; + mds = md_get_size(md); + for (;;) { + int error; + do { + error = 1; + if (md_starts(&c)) { + break; + } + if (addmd) { + if (md_update(&c, &(md_buf[0]), mds)) { + break; + } + } else { + addmd = 1; + } + if (md_update(&c, pass, datal)) + break; + if (md_finish(&c, &(md_buf[0]))) + break; + error = 0; + } while (0); + if (error) { + md_free_ctx(&c); + memset(md_buf, 0, MAX_MD_SIZE); + return 0; } - EVP_CIPHER_CTX evp; - EVP_CIPHER_CTX_init(&evp); - if (!EVP_CipherInit_ex(&evp, cipher, NULL, NULL, NULL, 1)) - { - LOGE("Cannot initialize cipher %s", supported_ciphers[method]); - exit(EXIT_FAILURE); + + i=0; + if (nkey) { + for (;;) { + if (nkey == 0) break; + if (i == mds) break; + if (key != NULL) + *(key++)=md_buf[i]; + nkey--; + i++; + } } - if (!EVP_CIPHER_CTX_set_key_length(&evp, enc_key_len)) - { - EVP_CIPHER_CTX_cleanup(&evp); - LOGE("Invalid key length: %d", enc_key_len); - exit(EXIT_FAILURE); + if (niv && (i != mds)) { + for (;;) { + if (niv == 0) break; + if (i == mds) break; + if (iv != NULL) + *(iv++)=md_buf[i]; + niv--; + i++; + } } - if (method > RC4) - { - EVP_CIPHER_CTX_set_padding(&evp, 1); + if ((nkey == 0) && (niv == 0)) break; + } + md_free_ctx(&c); + memset(md_buf, 0, MAX_MD_SIZE); + return rv; +#endif +} + +int rand_bytes(uint8_t *output, int len) +{ +#if defined(USE_CRYPTO_OPENSSL) + return RAND_bytes(output, len); +#elif defined(USE_CRYPTO_POLARSSL) + static entropy_context ec = {0}; + static ctr_drbg_context cd_ctx = {0}; + static unsigned char rand_initialised = 0; + const size_t blen = min(len, CTR_DRBG_MAX_REQUEST); + + if (!rand_initialised) { +#ifdef _WIN32 + HCRYPTPROV hProvider; + union { + unsigned __int64 seed; + BYTE buffer[8]; + } rand_buffer; + + hProvider = 0; + if (CryptAcquireContext(&hProvider, 0, 0, PROV_RSA_FULL, \ + CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { + CryptGenRandom(hProvider, 8, rand_buffer.buffer); + CryptReleaseContext(hProvider, 0); + } else { + rand_buffer.seed = (unsigned __int64) clock(); + } +#else + FILE *urand; + union { + uint64_t seed; + uint8_t buffer[8]; + } rand_buffer; + + urand = fopen("/dev/urandom", "r"); + if (urand) { + fread(&rand_buffer.seed, sizeof(rand_buffer.seed), 1, urand); + fclose(urand); + } else { + rand_buffer.seed = (uint64_t) clock(); } +#endif + entropy_init(&ec); + if (ctr_drbg_init(&cd_ctx, entropy_func, &ec, (const unsigned char *) rand_buffer.buffer, 8) != 0) { +#if POLARSSL_VERSION_NUMBER >= 0x01030000 + entropy_free(&ec); +#endif + FATAL("Failed to initialize random generator"); + } + rand_initialised = 1; + } +#ifdef DEBUG + int orig_len = len; + uint8_t *orig_output = output; +#endif + while (len > 0) { + if (ctr_drbg_random(&cd_ctx, output, blen) != 0) { + return 0; + } + output += blen; + len -= blen; + } + return 1; +#endif +} + +const cipher_kt_t *get_cipher_type(int method) +{ + if (method <= TABLE || method >= CIPHER_NUM) { + LOGE("get_cipher_type(): Illegal method"); + return NULL; + } + + const char *ciphername = supported_ciphers[method]; +#if defined(USE_CRYPTO_OPENSSL) + return EVP_get_cipherbyname(ciphername); +#elif defined(USE_CRYPTO_POLARSSL) + const char *polarname = supported_ciphers_polarssl[method]; + if (strcmp(polarname, CIPHER_UNSUPPORTED) == 0) { + LOGE("Cipher %s currently is not supported by PolarSSL library", ciphername); + FATAL("Unsupported cipher in PolarSSL"); + } + return cipher_info_from_string(polarname); +#endif +} + +const digest_type_t *get_digest_type(const char *digest) +{ + if (digest == NULL) { + LOGE("get_digest_type(): Digest name is null"); + return NULL; + } + +#if defined(USE_CRYPTO_OPENSSL) + return EVP_get_digestbyname(digest); +#elif defined(USE_CRYPTO_POLARSSL) + return md_info_from_string(digest); +#endif +} + +void cipher_context_init(cipher_ctx_t *evp, int method, int enc) +{ + if (method <= TABLE || method >= CIPHER_NUM) { + LOGE("cipher_context_init(): Illegal method"); + return; + } + + const char *ciphername = supported_ciphers[method]; + const cipher_kt_t *cipher = get_cipher_type(method); +#if defined(USE_CRYPTO_OPENSSL) + if (cipher == NULL) { + LOGE("Cipher %s not found in OpenSSL library", ciphername); + FATAL("Cannot initialize cipher"); + } + EVP_CIPHER_CTX_init(evp); + if (!EVP_CipherInit_ex(evp, cipher, NULL, NULL, NULL, enc)) { + LOGE("Cannot initialize cipher %s", ciphername); + exit(EXIT_FAILURE); + } + if (!EVP_CIPHER_CTX_set_key_length(evp, enc_key_len)) { + EVP_CIPHER_CTX_cleanup(evp); + LOGE("Invalid key length: %d", enc_key_len); + exit(EXIT_FAILURE); + } + if (method > RC4) { + EVP_CIPHER_CTX_set_padding(evp, 1); + } +#elif defined(USE_CRYPTO_POLARSSL) + if (cipher == NULL) { + LOGE("Cipher %s not found in PolarSSL library", ciphername); + FATAL("Cannot initialize PolarSSL cipher"); + } + if (cipher_init_ctx(evp, cipher) != 0) { + FATAL("Cannot initialize PolarSSL cipher context"); + } +#endif +} + +void cipher_context_set_iv(cipher_ctx_t *evp, uint8_t *iv, size_t iv_len, int enc) +{ + if (evp == NULL || iv == NULL) { + LOGE("cipher_context_set_keyiv(): Cipher context or IV is null"); + return; + } + if (enc) { + rand_bytes(iv, iv_len); + } +#if defined(USE_CRYPTO_OPENSSL) + if (!EVP_CipherInit_ex(evp, NULL, NULL, enc_key, iv, enc)) { + EVP_CIPHER_CTX_cleanup(evp); + FATAL("Cannot set key and IV"); + } +#elif defined(USE_CRYPTO_POLARSSL) + if (cipher_setkey(evp, enc_key, enc_key_len * 8, enc) != 0) { + cipher_free_ctx(evp); + FATAL("Cannot set PolarSSL cipher key"); + } +#if POLARSSL_VERSION_NUMBER >= 0x01030000 + if (cipher_set_iv(evp, iv, iv_len) != 0) { + cipher_free_ctx(evp); + FATAL("Cannot set PolarSSL cipher IV"); + } + if(cipher_reset(evp) != 0) { + cipher_free_ctx(evp); + FATAL("Cannot finalize PolarSSL cipher context"); + } +#else + if(cipher_reset(evp, iv) != 0) { + cipher_free_ctx(evp); + FATAL("Cannot set PolarSSL cipher IV"); + } +#endif +#endif +#ifdef DEBUG + dump("IV", iv); +#endif +} + +void cipher_context_release(cipher_ctx_t *evp) { +#if defined(USE_CRYPTO_OPENSSL) + EVP_CIPHER_CTX_cleanup(evp); +#elif defined(USE_CRYPTO_POLARSSL) + cipher_free_ctx(evp); +#endif +} + +int cipher_context_update(cipher_ctx_t *evp, uint8_t *output, int *olen, \ + const uint8_t *input, int ilen) { +#if defined(USE_CRYPTO_OPENSSL) + return EVP_CipherUpdate(evp, (uint8_t *) output, (size_t *) olen, \ + (const uint8_t *) input, (size_t) ilen); +#elif defined(USE_CRYPTO_POLARSSL) + return !cipher_update(evp, (const uint8_t *) input, (size_t) ilen, \ + (uint8_t *) output, (size_t *) olen); +#endif +} + +char* ss_encrypt_all(int buf_size, char *plaintext, ssize_t *len, int method) +{ + if (method > TABLE) + { + cipher_ctx_t evp; + cipher_context_init(&evp, method, 1); int c_len = *len + BLOCK_SIZE; int iv_len = 0; int err = 0; char *ciphertext = malloc(max(iv_len + c_len, buf_size)); - uint8_t iv[EVP_MAX_IV_LENGTH]; + uint8_t iv[MAX_IV_LENGTH]; iv_len = enc_iv_len; - RAND_bytes(iv, iv_len); - EVP_CipherInit_ex(&evp, NULL, NULL, enc_key, iv, 1); + cipher_context_set_iv(&evp, iv, iv_len, 1); memcpy(ciphertext, iv, iv_len); -#ifdef DEBUG - dump("IV", iv); -#endif - - err = EVP_EncryptUpdate(&evp, (uint8_t*)(ciphertext+iv_len), - &c_len, (const uint8_t *)plaintext, *len); + err = cipher_context_update(&evp, (uint8_t*)(ciphertext+iv_len), + &c_len, (const uint8_t *)plaintext, *len); if (!err) { free(ciphertext); free(plaintext); - EVP_CIPHER_CTX_cleanup(&evp); + cipher_context_release(&evp); return NULL; } @@ -229,7 +566,7 @@ char* ss_encrypt_all(int buf_size, char *plaintext, ssize_t *len, int method) *len = iv_len + c_len; free(plaintext); - EVP_CIPHER_CTX_cleanup(&evp); + cipher_context_release(&evp); return ciphertext; @@ -257,19 +594,15 @@ char* ss_encrypt(int buf_size, char *plaintext, ssize_t *len, struct enc_ctx *ct if (!ctx->init) { - uint8_t iv[EVP_MAX_IV_LENGTH]; + uint8_t iv[MAX_IV_LENGTH]; iv_len = enc_iv_len; - RAND_bytes(iv, iv_len); - EVP_CipherInit_ex(&ctx->evp, NULL, NULL, enc_key, iv, 1); + cipher_context_set_iv(&ctx->evp, iv, iv_len, 1); memcpy(ciphertext, iv, iv_len); ctx->init = 1; -#ifdef DEBUG - dump("IV", iv); -#endif } - err = EVP_EncryptUpdate(&ctx->evp, (uint8_t*)(ciphertext+iv_len), - &c_len, (const uint8_t *)plaintext, *len); + err = cipher_context_update(&ctx->evp, (uint8_t*)(ciphertext+iv_len), + &c_len, (const uint8_t *)plaintext, *len); if (!err) { free(ciphertext); @@ -302,51 +635,26 @@ char* ss_decrypt_all(int buf_size, char *ciphertext, ssize_t *len, int method) { if (method > TABLE) { - const EVP_CIPHER *cipher = EVP_get_cipherbyname(supported_ciphers[method]); - if (cipher == NULL) - { - LOGE("Cipher %s not found in OpenSSL library", supported_ciphers[method]); - FATAL("Cannot initialize cipher"); - } - EVP_CIPHER_CTX evp; - EVP_CIPHER_CTX_init(&evp); - if (!EVP_CipherInit_ex(&evp, cipher, NULL, NULL, NULL, 0)) - { - LOGE("Cannot initialize cipher %s", supported_ciphers[method]); - exit(EXIT_FAILURE); - } - if (!EVP_CIPHER_CTX_set_key_length(&evp, enc_key_len)) - { - EVP_CIPHER_CTX_cleanup(&evp); - LOGE("Invalid key length: %d", enc_key_len); - exit(EXIT_FAILURE); - } - if (method > RC4) - { - EVP_CIPHER_CTX_set_padding(&evp, 1); - } + cipher_ctx_t evp; + cipher_context_init(&evp, method, 0); int p_len = *len + BLOCK_SIZE; int iv_len = 0; int err = 0; char *plaintext = malloc(max(p_len, buf_size)); - uint8_t iv[EVP_MAX_IV_LENGTH]; + uint8_t iv[MAX_IV_LENGTH]; iv_len = enc_iv_len; memcpy(iv, ciphertext, iv_len); - EVP_CipherInit_ex(&evp, NULL, NULL, enc_key, iv, 0); + cipher_context_set_iv(&evp, iv, iv_len, 0); -#ifdef DEBUG - dump("IV", iv); -#endif - - err = EVP_DecryptUpdate(&evp, (uint8_t*)plaintext, &p_len, - (const uint8_t*)(ciphertext + iv_len), *len - iv_len); + err = cipher_context_update(&evp, (uint8_t*)plaintext, &p_len, + (const uint8_t*)(ciphertext + iv_len), *len - iv_len); if (!err) { free(ciphertext); free(plaintext); - EVP_CIPHER_CTX_cleanup(&evp); + cipher_context_release(&evp); return NULL; } @@ -357,7 +665,7 @@ char* ss_decrypt_all(int buf_size, char *ciphertext, ssize_t *len, int method) *len = p_len; free(ciphertext); - EVP_CIPHER_CTX_cleanup(&evp); + cipher_context_release(&evp); return plaintext; } else @@ -383,18 +691,15 @@ char* ss_decrypt(int buf_size, char *ciphertext, ssize_t *len, struct enc_ctx *c if (!ctx->init) { - uint8_t iv[EVP_MAX_IV_LENGTH]; + uint8_t iv[MAX_IV_LENGTH]; iv_len = enc_iv_len; memcpy(iv, ciphertext, iv_len); - EVP_CipherInit_ex(&ctx->evp, NULL, NULL, enc_key, iv, 0); + cipher_context_set_iv(&ctx->evp, iv, iv_len, 0); ctx->init = 1; -#ifdef DEBUG - dump("IV", iv); -#endif } - err = EVP_DecryptUpdate(&ctx->evp, (uint8_t*)plaintext, &p_len, - (const uint8_t*)(ciphertext + iv_len), *len - iv_len); + err = cipher_context_update(&ctx->evp, (uint8_t*)plaintext, &p_len, + (const uint8_t*)(ciphertext + iv_len), *len - iv_len); if (!err) { @@ -426,50 +731,37 @@ char* ss_decrypt(int buf_size, char *ciphertext, ssize_t *len, struct enc_ctx *c void enc_ctx_init(int method, struct enc_ctx *ctx, int enc) { - const EVP_CIPHER *cipher = EVP_get_cipherbyname(supported_ciphers[method]); - if (cipher == NULL) - { - LOGE("Cipher %s not found in OpenSSL library", supported_ciphers[method]); - FATAL("Cannot initialize cipher"); - } memset(ctx, 0, sizeof(struct enc_ctx)); - - EVP_CIPHER_CTX *evp = &ctx->evp; - - EVP_CIPHER_CTX_init(evp); - if (!EVP_CipherInit_ex(evp, cipher, NULL, NULL, NULL, enc)) - { - LOGE("Cannot initialize cipher %s", supported_ciphers[method]); - exit(EXIT_FAILURE); - } - if (!EVP_CIPHER_CTX_set_key_length(evp, enc_key_len)) - { - EVP_CIPHER_CTX_cleanup(evp); - LOGE("Invalid key length: %d", enc_key_len); - exit(EXIT_FAILURE); - } - if (method > RC4) - { - EVP_CIPHER_CTX_set_padding(evp, 1); - } + cipher_context_init(&ctx->evp, method, enc); } void enc_key_init(int method, const char *pass) { + if (method <= TABLE || method >= CIPHER_NUM) { + LOGE("enc_key_init(): Illegal method"); + return; + } + +#if defined(USE_CRYPTO_OPENSSL) OpenSSL_add_all_algorithms(); +#endif - uint8_t iv[EVP_MAX_IV_LENGTH]; - const EVP_CIPHER *cipher = EVP_get_cipherbyname(supported_ciphers[method]); - if (cipher == NULL) - { - LOGE("Cipher %s not found in OpenSSL library", supported_ciphers[method]); + uint8_t iv[MAX_IV_LENGTH]; + const cipher_kt_t *cipher = get_cipher_type(method); + if (cipher == NULL) { + LOGE("Cipher %s not found in crypto library", supported_ciphers[method]); FATAL("Cannot initialize cipher"); - return; + } + const digest_type_t *md = get_digest_type("MD5"); + if (md == NULL) { + FATAL("MD5 Digest not found in crypto library"); } - enc_key_len = EVP_BytesToKey(cipher, EVP_md5(), NULL, (uint8_t *)pass, - strlen(pass), 1, enc_key, iv); - enc_iv_len = EVP_CIPHER_iv_length(cipher); + enc_key_len = bytes_to_key(cipher, md, (const uint8_t *) pass, enc_key, iv); + if (enc_key_len == 0) { + FATAL("Cannot generate key and IV"); + } + enc_iv_len = cipher_iv_size(cipher); } int enc_init(const char *pass, const char *method) diff --git a/src/encrypt.h b/src/encrypt.h index 65d62206..c940a9f9 100644 --- a/src/encrypt.h +++ b/src/encrypt.h @@ -21,7 +21,28 @@ #include #include +#if defined(USE_CRYPTO_OPENSSL) + #include +typedef EVP_CIPHER cipher_kt_t; +typedef EVP_CIPHER_CTX cipher_ctx_t; +typedef EVP_MD digest_type_t; +#define MAX_KEY_LENGTH EVP_MAX_KEY_LENGTH +#define MAX_IV_LENGTH EVP_MAX_IV_LENGTH +#define MAX_MD_SIZE EVP_MAX_MD_SIZE + +#elif defined(USE_CRYPTO_POLARSSL) + +#include +#include +typedef cipher_info_t cipher_kt_t; +typedef cipher_context_t cipher_ctx_t; +typedef md_info_t digest_type_t; +#define MAX_KEY_LENGTH 64 +#define MAX_IV_LENGTH POLARSSL_MAX_IV_LENGTH +#define MAX_MD_SIZE POLARSSL_MD_MAX_SIZE + +#endif #ifdef HAVE_STDINT_H #include @@ -54,7 +75,7 @@ struct enc_ctx { uint8_t init; - EVP_CIPHER_CTX evp; + cipher_ctx_t evp; }; char* ss_encrypt_all(int buf_size, char *plaintext, ssize_t *len, int method); @@ -64,5 +85,7 @@ char* ss_decrypt(int buf_size, char *ciphertext, ssize_t *len, struct enc_ctx *c void enc_ctx_init(int method, struct enc_ctx *ctx, int enc); int enc_init(const char *pass, const char *method); int enc_get_iv_len(void); +void cipher_context_release(cipher_ctx_t *evp); +unsigned char *enc_md5(const unsigned char *d, size_t n, unsigned char *md); #endif // _ENCRYPT_H diff --git a/src/local.c b/src/local.c index 867cc17d..5a69aa13 100644 --- a/src/local.c +++ b/src/local.c @@ -700,12 +700,12 @@ static void free_server(struct server *server) } if (server->e_ctx != NULL) { - EVP_CIPHER_CTX_cleanup(&server->e_ctx->evp); + cipher_context_release(&server->e_ctx->evp); free(server->e_ctx); } if (server->d_ctx != NULL) { - EVP_CIPHER_CTX_cleanup(&server->d_ctx->evp); + cipher_context_release(&server->d_ctx->evp); free(server->d_ctx); } if (server->buf) diff --git a/src/redir.c b/src/redir.c index ff254949..99e56af2 100644 --- a/src/redir.c +++ b/src/redir.c @@ -557,12 +557,12 @@ void free_server(struct server *server) } if (server->e_ctx != NULL) { - EVP_CIPHER_CTX_cleanup(&server->e_ctx->evp); + cipher_context_release(&server->e_ctx->evp); free(server->e_ctx); } if (server->d_ctx != NULL) { - EVP_CIPHER_CTX_cleanup(&server->d_ctx->evp); + cipher_context_release(&server->d_ctx->evp); free(server->d_ctx); } if (server->buf != NULL) diff --git a/src/server.c b/src/server.c index b7de0f90..befac8e1 100644 --- a/src/server.c +++ b/src/server.c @@ -830,12 +830,12 @@ void free_server(struct server *server) } if (server->e_ctx != NULL) { - EVP_CIPHER_CTX_cleanup(&server->e_ctx->evp); + cipher_context_release(&server->e_ctx->evp); free(server->e_ctx); } if (server->d_ctx != NULL) { - EVP_CIPHER_CTX_cleanup(&server->d_ctx->evp); + cipher_context_release(&server->d_ctx->evp); free(server->d_ctx); } if (server->buf != NULL) diff --git a/src/udprelay.c b/src/udprelay.c index 65b3928a..ff30107b 100644 --- a/src/udprelay.c +++ b/src/udprelay.c @@ -31,8 +31,6 @@ #include "win32.h" #endif -#include - #include "utils.h" #include "udprelay.h" #include "cache.h" @@ -89,7 +87,7 @@ static char *hash_key(const char *header, const int header_len, const struct soc memcpy(key, addr, sizeof(struct sockaddr)); memcpy(key + sizeof(struct sockaddr), header, header_len); - return (char*) MD5((const uint8_t *)key, sizeof(struct sockaddr) + header_len, NULL); + return (char*) enc_md5((const uint8_t *)key, sizeof(struct sockaddr) + header_len, NULL); } static int parse_udprealy_header(const char* buf, const int buf_len, char *host, char *port) diff --git a/src/utils.c b/src/utils.c index a575d90f..61c24279 100644 --- a/src/utils.c +++ b/src/utils.c @@ -83,7 +83,7 @@ void usage() printf(" ss-[local|redir|server]\n"); printf(" -s host name or ip address of your remote server\n"); printf(" -p port number of your remote server\n"); - printf(" -l > port number of your local server\n"); + printf(" -l port number of your local server\n"); printf(" -k password of your remote server\n"); printf("\n"); printf(" [-m ] encrypt method, supporting table, rc4,\n");