From ef0402eb10bfe07a0cb98f33aa670707e4593d45 Mon Sep 17 00:00:00 2001 From: Max Lv Date: Mon, 6 Feb 2017 17:02:04 +0800 Subject: [PATCH] Add `--key` option to set key directly (#1207) --- doc/shadowsocks-libev.asciidoc | 6 ++ doc/ss-local.asciidoc | 5 ++ doc/ss-redir.asciidoc | 8 +- doc/ss-server.asciidoc | 5 ++ doc/ss-tunnel.asciidoc | 5 ++ m4/sodium.m4 | 4 +- src/Makefile.am | 5 +- src/aead.c | 16 ++-- src/aead.h | 3 +- src/base64.c | 106 +++++++++++++++++++++++++ src/base64.h | 54 +++++++++++++ src/common.h | 2 + src/crypto.c | 139 ++++++++++++++++++--------------- src/crypto.h | 20 ++--- src/jconf.c | 2 + src/jconf.h | 1 + src/local.c | 16 +++- src/manager.c | 2 + src/manager.h | 1 + src/redir.c | 16 +++- src/server.c | 15 +++- src/stream.c | 13 +-- src/stream.h | 2 +- src/tunnel.c | 16 +++- src/utils.c | 4 + 25 files changed, 363 insertions(+), 103 deletions(-) create mode 100644 src/base64.c create mode 100644 src/base64.h diff --git a/doc/shadowsocks-libev.asciidoc b/doc/shadowsocks-libev.asciidoc index fc625ae0..72411e21 100644 --- a/doc/shadowsocks-libev.asciidoc +++ b/doc/shadowsocks-libev.asciidoc @@ -45,8 +45,14 @@ Set the local port number. Not available in server nor manager mode. -k :: +--password :: Set the password. The server and the client should use the same password. +--key :: +Set the key directly. The key should be encoded with URL-safe Base64. ++ +Not available in manager mode. + -m :: Set the cipher. + diff --git a/doc/ss-local.asciidoc b/doc/ss-local.asciidoc index 4ef443b1..f3e54525 100644 --- a/doc/ss-local.asciidoc +++ b/doc/ss-local.asciidoc @@ -15,6 +15,7 @@ SYNOPSIS [-a ] [-b ] [--fast-open] [--reuse-port] [--acl ] [--mtu ] [--plugin ] [--plugin-opts ] [--key :: +--password :: Set the password. The server and the client should use the same password. +--key :: +Set the key directly. The key should be encoded with URL-safe Base64. + -m :: Set the cipher. + diff --git a/doc/ss-redir.asciidoc b/doc/ss-redir.asciidoc index 954334af..7a1fdc62 100644 --- a/doc/ss-redir.asciidoc +++ b/doc/ss-redir.asciidoc @@ -14,6 +14,7 @@ SYNOPSIS [-t ] [-c ] [-b ] [-a ] [-n ] [--mtu ] [--plugin ] [--plugin-opts ] [--key :: -Set the password. The server and the client should use the same -password. +--password :: +Set the password. The server and the client should use the same password. + +--key :: +Set the key directly. The key should be encoded with URL-safe Base64. -m :: Set the cipher. diff --git a/doc/ss-server.asciidoc b/doc/ss-server.asciidoc index 0d30c418..29dd76b5 100644 --- a/doc/ss-server.asciidoc +++ b/doc/ss-server.asciidoc @@ -17,6 +17,7 @@ SYNOPSIS [--acl ] [--mtu ] [--manager-address ] [--plugin ] [--plugin-opts ] [--key :: +--password :: Set the password. The server and the client should use the same password. +--key :: +Set the key directly. The key should be encoded with URL-safe Base64. + -m :: Set the cipher. + diff --git a/doc/ss-tunnel.asciidoc b/doc/ss-tunnel.asciidoc index 7a0c380e..41602086 100644 --- a/doc/ss-tunnel.asciidoc +++ b/doc/ss-tunnel.asciidoc @@ -15,6 +15,7 @@ SYNOPSIS [-b ] [-a ] [-n ] [-L addr:port] [--mtu ] [--mptcp] [--reuse-port] [--plugin ] [--plugin-opts ] DESCRIPTION ----------- @@ -40,8 +41,12 @@ Set the server's port number. Set the local port number. -k :: +--password :: Set the password. The server and the client should use the same password. +--key :: +Set the key directly. The key should be encoded with URL-safe Base64. + -m :: Set the cipher. + diff --git a/m4/sodium.m4 b/m4/sodium.m4 index 46d21db4..c3a5f3fd 100644 --- a/m4/sodium.m4 +++ b/m4/sodium.m4 @@ -30,11 +30,11 @@ AC_DEFUN([ss_SODIUM], AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ #include ], [ - #if SODIUM_LIBRARY_VERSION_MAJOR < 9 + #if SODIUM_LIBRARY_VERSION_MAJOR < 8 # error #endif ])], [AC_MSG_RESULT([checking for version of libsodium... yes])], - [AC_MSG_ERROR([Wrong libsodium: version >= 1.0.9 required])]) + [AC_MSG_ERROR([Wrong libsodium: version >= 1.0.8 required])]) ]) diff --git a/src/Makefile.am b/src/Makefile.am index e17bee0d..955fb570 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -25,7 +25,8 @@ sni_src = http.c \ crypto_src = crypto.c \ aead.c \ - stream.c + stream.c \ + base64.c plugin_src = plugin.c @@ -111,6 +112,6 @@ libshadowsocks_libev_la_LIBADD = $(ss_local_LDADD) include_HEADERS = shadowsocks.h noinst_HEADERS = acl.h crypto.h stream.h aead.h json.h netutils.h redir.h server.h tls.h uthash.h \ - cache.h http.h local.h plugin.h resolv.h tunnel.h utils.h \ + cache.h http.h local.h plugin.h resolv.h tunnel.h utils.h base64.h \ common.h jconf.h manager.h protocol.h rule.h socks5.h udprelay.h EXTRA_DIST = ss-nat diff --git a/src/aead.c b/src/aead.c index f6678c47..0ee6872d 100644 --- a/src/aead.c +++ b/src/aead.c @@ -138,7 +138,6 @@ dump(char *tag, char *text, int len) printf("0x%02x ", (uint8_t)text[i]); printf("\n"); } - #endif const char *supported_aead_ciphers[AEAD_CIPHER_NUM] = { @@ -691,7 +690,7 @@ aead_decrypt(buffer_t *ciphertext, cipher_ctx_t *cipher_ctx, size_t capacity) } cipher_t * -aead_key_init(int method, const char *pass) +aead_key_init(int method, const char *pass, const char *key) { if (method < AES128GCM || method >= AEAD_CIPHER_NUM) { LOGE("aead_key_init(): Illegal method"); @@ -724,8 +723,12 @@ aead_key_init(int method, const char *pass) FATAL("Cannot initialize cipher"); } - cipher->key_len = crypto_derive_key(cipher, pass, cipher->key, - supported_aead_ciphers_key_size[method], 2); + if (key != NULL) + cipher->key_len = crypto_parse_key(key, cipher->key, + supported_aead_ciphers_key_size[method]); + else + cipher->key_len = crypto_derive_key(key, cipher->key, + supported_aead_ciphers_key_size[method]); if (cipher->key_len == 0) { FATAL("Cannot generate key and nonce"); @@ -739,7 +742,7 @@ aead_key_init(int method, const char *pass) } cipher_t * -aead_init(const char *pass, const char *method) +aead_init(const char *pass, const char *key, const char *method) { int m = AES128GCM; if (method != NULL) { @@ -753,5 +756,6 @@ aead_init(const char *pass, const char *method) m = AES256GCM; } } - return aead_key_init(m, pass); + return aead_key_init(m, pass, key); } + diff --git a/src/aead.h b/src/aead.h index b9fbc559..5095da50 100644 --- a/src/aead.h +++ b/src/aead.h @@ -41,6 +41,7 @@ int aead_decrypt(buffer_t *, cipher_ctx_t *, size_t); void aead_ctx_init(cipher_t *, cipher_ctx_t *, int); void aead_ctx_release(cipher_ctx_t *); -cipher_t *aead_init(const char *pass, const char *method); + +cipher_t *aead_init(const char *pass, const char *key, const char *method); #endif // _AEAD_H diff --git a/src/base64.c b/src/base64.c new file mode 100644 index 00000000..e1147fa4 --- /dev/null +++ b/src/base64.c @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2006 Ryan Martell. (rdm4@martellventures.com) + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @brief Base64 encode/decode + * @author Ryan Martell (with lots of Michael) + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include "base64.h" + +/* ---------------- private code */ +static const uint8_t map2[] = +{ + 0xff, 0xff, 0x3e, 0xff, 0xff, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, + 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, + 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33 +}; + +int base64_decode(uint8_t *out, const char *in, int out_size) +{ + int i, v; + uint8_t *dst = out; + + v = 0; + for (i = 0; in[i] && in[i] != '='; i++) { + unsigned int index = in[i] - 43; + if (index >= sizeof(map2) || map2[index] == 0xff) + return -1; + v = (v << 6) + map2[index]; + if (i & 3) { + if (dst - out < out_size) { + *dst++ = v >> (6 - 2 * (i & 3)); + } + } + } + + return dst - out; +} + +/***************************************************************************** +* b64_encode: Stolen from VLC's http.c. +* Simplified by Michael. +* Fixed edge cases and made it work from data (vs. strings) by Ryan. +*****************************************************************************/ + +char *base64_encode(char *out, int out_size, const uint8_t *in, int in_size) +{ + static const char b64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; + char *ret, *dst; + unsigned i_bits = 0; + int i_shift = 0; + int bytes_remaining = in_size; + + if (in_size >= UINT_MAX / 4 || + out_size < BASE64_SIZE(in_size)) + return NULL; + ret = dst = out; + while (bytes_remaining) { + i_bits = (i_bits << 8) + *in++; + bytes_remaining--; + i_shift += 8; + + do { + *dst++ = b64[(i_bits << 6 >> i_shift) & 0x3f]; + i_shift -= 6; + } while (i_shift > 6 || (bytes_remaining == 0 && i_shift > 0)); + } + while ((dst - ret) & 3) + *dst++ = '='; + *dst = '\0'; + + return ret; +} diff --git a/src/base64.h b/src/base64.h new file mode 100644 index 00000000..01bcda57 --- /dev/null +++ b/src/base64.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2006 Ryan Martell. (rdm4@martellventures.com) + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef BASE64_H +#define BASE64_H + +#include + +/** + * Decode a base64-encoded string. + * + * @param out buffer for decoded data + * @param in null-terminated input string + * @param out_size size in bytes of the out buffer, must be at + * least 3/4 of the length of in + * @return number of bytes written, or a negative value in case of + * invalid input + */ +int base64_decode(uint8_t *out, const char *in, int out_size); + +/** + * Encode data to base64 and null-terminate. + * + * @param out buffer for encoded data + * @param out_size size in bytes of the output buffer, must be at + * least BASE64_SIZE(in_size) + * @param in_size size in bytes of the 'in' buffer + * @return 'out' or NULL in case of error + */ +char *base64_encode(char *out, int out_size, const uint8_t *in, int in_size); + +/** + * Calculate the output size needed to base64-encode x bytes. + */ +#define BASE64_SIZE(x) (((x)+2) / 3 * 4 + 1) + +#endif /* BASE64_H */ diff --git a/src/common.h b/src/common.h index cd16e185..44b9cf1a 100644 --- a/src/common.h +++ b/src/common.h @@ -67,6 +67,8 @@ enum { GETOPT_VAL_MPTCP, GETOPT_VAL_PLUGIN, GETOPT_VAL_PLUGIN_OPTS, + GETOPT_VAL_PASSWORD, + GETOPT_VAL_KEY, GETOPT_VAL_MANAGER_ADDRESS, GETOPT_VAL_EXECUTABLE }; diff --git a/src/crypto.c b/src/crypto.c index adc61147..ec6f2465 100644 --- a/src/crypto.c +++ b/src/crypto.c @@ -28,6 +28,7 @@ #include #include +#include "base64.h" #include "cache.h" #include "crypto.h" #include "stream.h" @@ -100,66 +101,8 @@ crypto_md5(const unsigned char *d, size_t n, unsigned char *md) return md; } -int -crypto_derive_key(const cipher_t *cipher, const char *pass, - uint8_t *key, size_t nkey, int version) -{ - if (version == 2) { - const unsigned char salt[crypto_pwhash_SALTBYTES] = { - 's', 'h', 'a', 'd', 'o', 'w', 's', 'o', - 'c', 'k', 's', ' ', 'h', 'a', 's', 'h' - }; - int err = crypto_pwhash (key, nkey, (char*)pass, strlen(pass), salt, - crypto_pwhash_OPSLIMIT_INTERACTIVE, crypto_pwhash_MEMLIMIT_INTERACTIVE, - crypto_pwhash_ALG_DEFAULT); - if (err) - FATAL("Out of memory when doing password hashing"); - else - return nkey; - } - - size_t datal; - datal = strlen((const char *)pass); - - const digest_type_t *md = mbedtls_md_info_from_string("MD5"); - if (md == NULL) { - FATAL("MD5 Digest not found in crypto library"); - } - - mbedtls_md_context_t c; - unsigned char md_buf[MAX_MD_SIZE]; - int addmd; - unsigned int i, j, mds; - - mds = mbedtls_md_get_size(md); - memset(&c, 0, sizeof(mbedtls_md_context_t)); - - if (pass == NULL) - return nkey; - if (mbedtls_md_setup(&c, md, 1)) - return 0; - - for (j = 0, addmd = 0; j < nkey; addmd++) { - mbedtls_md_starts(&c); - if (addmd) { - mbedtls_md_update(&c, md_buf, mds); - } - mbedtls_md_update(&c, (uint8_t *)pass, datal); - mbedtls_md_finish(&c, &(md_buf[0])); - - for (i = 0; i < mds; i++, j++) { - if (j >= nkey) - break; - key[j] = md_buf[i]; - } - } - - mbedtls_md_free(&c); - return nkey; -} - crypto_t * -crypto_init(const char *password, const char *method) +crypto_init(const char *password, const char *key, const char *method) { int i, m = -1; @@ -178,7 +121,7 @@ crypto_init(const char *password, const char *method) break; } if (m != -1) { - cipher_t *cipher = stream_init(password, method); + cipher_t *cipher = stream_init(password, key, method); if (cipher == NULL) return NULL; crypto_t *crypto = (crypto_t *)malloc(sizeof(crypto_t)); @@ -189,7 +132,7 @@ crypto_init(const char *password, const char *method) .encrypt = &stream_encrypt, .decrypt = &stream_decrypt, .ctx_init = &stream_ctx_init, - .ctx_release = &stream_ctx_release + .ctx_release = &stream_ctx_release, }; memcpy(crypto, &tmp, sizeof(crypto_t)); return crypto; @@ -201,7 +144,7 @@ crypto_init(const char *password, const char *method) break; } if (m != -1) { - cipher_t *cipher = aead_init(password, method); + cipher_t *cipher = aead_init(password, key, method); if (cipher == NULL) return NULL; crypto_t *crypto = (crypto_t *)ss_malloc(sizeof(crypto_t)); @@ -212,7 +155,7 @@ crypto_init(const char *password, const char *method) .encrypt = &aead_encrypt, .decrypt = &aead_decrypt, .ctx_init = &aead_ctx_init, - .ctx_release = &aead_ctx_release + .ctx_release = &aead_ctx_release, }; memcpy(crypto, &tmp, sizeof(crypto_t)); return crypto; @@ -222,3 +165,73 @@ crypto_init(const char *password, const char *method) LOGE("invalid cipher name: %s", method); return NULL; } + +int +crypto_derive_key(const char *pass, uint8_t *key, size_t key_len) +{ + size_t datal; + datal = strlen((const char *)pass); + + const digest_type_t *md = mbedtls_md_info_from_string("MD5"); + if (md == NULL) { + FATAL("MD5 Digest not found in crypto library"); + } + + mbedtls_md_context_t c; + unsigned char md_buf[MAX_MD_SIZE]; + int addmd; + unsigned int i, j, mds; + + mds = mbedtls_md_get_size(md); + memset(&c, 0, sizeof(mbedtls_md_context_t)); + + if (pass == NULL) + return key_len; + if (mbedtls_md_setup(&c, md, 1)) + return 0; + + for (j = 0, addmd = 0; j < key_len; addmd++) { + mbedtls_md_starts(&c); + if (addmd) { + mbedtls_md_update(&c, md_buf, mds); + } + mbedtls_md_update(&c, (uint8_t *)pass, datal); + mbedtls_md_finish(&c, &(md_buf[0])); + + for (i = 0; i < mds; i++, j++) { + if (j >= key_len) + break; + key[j] = md_buf[i]; + } + } + + mbedtls_md_free(&c); + return key_len; +} + +int +crypto_parse_key(const char *base64, uint8_t *key, size_t key_len) +{ + size_t base64_len = strlen(base64); + int out_len = BASE64_SIZE(base64_len); + uint8_t out[out_len]; + + out_len = base64_decode(out, base64, out_len); + if (out_len > 0 && out_len >= key_len) { + memcpy(key, out, key_len); +#ifdef DEBUG + dump("KEY", (char*)key, key_len); +#endif + return key_len; + } + + out_len = BASE64_SIZE(key_len); + char out_key[out_len]; + rand_bytes(key, key_len); + base64_encode(out_key, out_len, key, key_len); + LOGE("Invalid key for your chosen cipher!"); + LOGE("It requires a %zu-byte key encoded with URL-safe Base64", key_len); + LOGE("Generating a new random key: %s", out_key); + FATAL("Please use the key above or input a valid key"); + return key_len; +} diff --git a/src/crypto.h b/src/crypto.h index ac9474f5..424420dc 100644 --- a/src/crypto.h +++ b/src/crypto.h @@ -100,17 +100,17 @@ typedef struct crypto { void(*const ctx_release)(cipher_ctx_t *); } crypto_t; -int balloc(buffer_t *ptr, size_t capacity); -int brealloc(buffer_t *ptr, size_t len, size_t capacity); -int bprepend(buffer_t *dst, buffer_t *src, size_t capacity); -void bfree(buffer_t *ptr); -int rand_bytes(void *output, int len); +int balloc(buffer_t *, size_t); +int brealloc(buffer_t *, size_t, size_t); +int bprepend(buffer_t *, buffer_t *, size_t); +void bfree(buffer_t *); +int rand_bytes(void *, int); -crypto_t *crypto_init(const char *password, const char *method); -unsigned char *crypto_md5(const unsigned char *d, size_t n, - unsigned char *md); -int crypto_derive_key(const cipher_t *cipher, const char *pass, - uint8_t *key, size_t nkey, int version); +crypto_t *crypto_init(const char *, const char *, const char *); +unsigned char *crypto_md5(const unsigned char *, size_t, unsigned char *); + +int crypto_derive_key(const char *, uint8_t *, size_t); +int crypto_parse_key(const char *, uint8_t *, size_t); extern struct cache *nonce_cache; extern const char *supported_stream_ciphers[]; diff --git a/src/jconf.c b/src/jconf.c index 3e3c772d..c1b0ca47 100644 --- a/src/jconf.c +++ b/src/jconf.c @@ -198,6 +198,8 @@ read_jconf(const char *file) conf.local_port = to_string(value); } else if (strcmp(name, "password") == 0) { conf.password = to_string(value); + } else if (strcmp(name, "key") == 0) { + conf.key = to_string(value); } else if (strcmp(name, "method") == 0) { conf.method = to_string(value); } else if (strcmp(name, "timeout") == 0) { diff --git a/src/jconf.h b/src/jconf.h index 5411b57b..89cb1744 100644 --- a/src/jconf.h +++ b/src/jconf.h @@ -53,6 +53,7 @@ typedef struct { char *local_addr; char *local_port; char *password; + char *key; char *method; char *timeout; char *user; diff --git a/src/local.c b/src/local.c index 7fde3c55..1a409470 100644 --- a/src/local.c +++ b/src/local.c @@ -1173,6 +1173,7 @@ main(int argc, char **argv) char *local_port = NULL; char *local_addr = NULL; char *password = NULL; + char *key = NULL; char *timeout = NULL; char *method = NULL; char *pid_path = NULL; @@ -1199,6 +1200,8 @@ main(int argc, char **argv) { "mptcp", no_argument, NULL, GETOPT_VAL_MPTCP }, { "plugin", required_argument, NULL, GETOPT_VAL_PLUGIN }, { "plugin-opts", required_argument, NULL, GETOPT_VAL_PLUGIN_OPTS }, + { "password", required_argument, NULL, GETOPT_VAL_PASSWORD }, + { "key", required_argument, NULL, GETOPT_VAL_KEY }, { "help", no_argument, NULL, GETOPT_VAL_HELP }, { NULL, 0, NULL, 0 } }; @@ -1236,6 +1239,9 @@ main(int argc, char **argv) case GETOPT_VAL_PLUGIN_OPTS: plugin_opts = optarg; break; + case GETOPT_VAL_KEY: + key = optarg; + break; case GETOPT_VAL_REUSE_PORT: reuse_port = 1; break; @@ -1251,6 +1257,7 @@ main(int argc, char **argv) case 'l': local_port = optarg; break; + case GETOPT_VAL_PASSWORD: case 'k': password = optarg; break; @@ -1339,6 +1346,9 @@ main(int argc, char **argv) if (password == NULL) { password = conf->password; } + if (key == NULL) { + key = conf->key; + } if (method == NULL) { method = conf->method; } @@ -1380,7 +1390,7 @@ main(int argc, char **argv) #ifndef HAVE_LAUNCHD local_port == NULL || #endif - password == NULL) { + (password == NULL && key == NULL)) { usage(); exit(EXIT_FAILURE); } @@ -1464,7 +1474,7 @@ main(int argc, char **argv) // Setup keys LOGI("initializing ciphers... %s", method); - crypto = crypto_init(password, method); + crypto = crypto_init(password, key, method); if (crypto == NULL) FATAL("failed to initialize ciphers"); @@ -1645,7 +1655,7 @@ start_ss_local_server(profile_t profile) // Setup keys LOGI("initializing ciphers... %s", method); - crypto = crypto_init(password, method); + crypto = crypto_init(password, NULL, method); if (crypto == NULL) FATAL("failed to init ciphers"); diff --git a/src/manager.c b/src/manager.c index 1e033e7d..d10aa226 100644 --- a/src/manager.c +++ b/src/manager.c @@ -910,6 +910,7 @@ main(int argc, char **argv) { "mtu", required_argument, NULL, GETOPT_VAL_MTU }, { "plugin", required_argument, NULL, GETOPT_VAL_PLUGIN }, { "plugin-opts", required_argument, NULL, GETOPT_VAL_PLUGIN_OPTS }, + { "password", required_argument, NULL, GETOPT_VAL_PASSWORD }, { "help", no_argument, NULL, GETOPT_VAL_HELP }, { NULL, 0, NULL, 0 } }; @@ -950,6 +951,7 @@ main(int argc, char **argv) server_host[server_num++] = optarg; } break; + case GETOPT_VAL_PASSWORD: case 'k': password = optarg; break; diff --git a/src/manager.h b/src/manager.h index ccdcaded..6ecf6735 100644 --- a/src/manager.h +++ b/src/manager.h @@ -40,6 +40,7 @@ struct manager_ctx { int mode; int auth; char *password; + char *key; char *timeout; char *method; char *iface; diff --git a/src/redir.c b/src/redir.c index a13da640..a595ab8e 100644 --- a/src/redir.c +++ b/src/redir.c @@ -786,6 +786,7 @@ main(int argc, char **argv) char *local_port = NULL; char *local_addr = NULL; char *password = NULL; + char *key = NULL; char *timeout = NULL; char *method = NULL; char *pid_path = NULL; @@ -807,6 +808,8 @@ main(int argc, char **argv) { "plugin", required_argument, NULL, GETOPT_VAL_PLUGIN }, { "plugin-opts", required_argument, NULL, GETOPT_VAL_PLUGIN_OPTS }, { "reuse-port", no_argument, NULL, GETOPT_VAL_REUSE_PORT }, + { "password", required_argument, NULL, GETOPT_VAL_PASSWORD }, + { "key", required_argument, NULL, GETOPT_VAL_KEY }, { "help", no_argument, NULL, GETOPT_VAL_HELP }, { NULL, 0, NULL, 0 } }; @@ -832,6 +835,9 @@ main(int argc, char **argv) case GETOPT_VAL_PLUGIN_OPTS: plugin_opts = optarg; break; + case GETOPT_VAL_KEY: + key = optarg; + break; case GETOPT_VAL_REUSE_PORT: reuse_port = 1; break; @@ -847,6 +853,7 @@ main(int argc, char **argv) case 'l': local_port = optarg; break; + case GETOPT_VAL_PASSWORD: case 'k': password = optarg; break; @@ -928,6 +935,9 @@ main(int argc, char **argv) if (password == NULL) { password = conf->password; } + if (key == NULL) { + key = conf->key; + } if (method == NULL) { method = conf->method; } @@ -962,8 +972,8 @@ main(int argc, char **argv) #endif } - if (remote_num == 0 || remote_port == NULL || - local_port == NULL || password == NULL) { + if (remote_num == 0 || remote_port == NULL || local_port == NULL + || (password == NULL && key == NULL)) { usage(); exit(EXIT_FAILURE); } @@ -1044,7 +1054,7 @@ main(int argc, char **argv) // Setup keys LOGI("initializing ciphers... %s", method); - crypto = crypto_init(password, method); + crypto = crypto_init(password, key, method); if (crypto == NULL) FATAL("failed to initialize ciphers"); diff --git a/src/server.c b/src/server.c index f2512859..ac94cfa8 100644 --- a/src/server.c +++ b/src/server.c @@ -1338,6 +1338,7 @@ main(int argc, char **argv) int mtu = 0; char *user = NULL; char *password = NULL; + char *key = NULL; char *timeout = NULL; char *method = NULL; char *pid_path = NULL; @@ -1364,6 +1365,8 @@ main(int argc, char **argv) { "help", no_argument, NULL, GETOPT_VAL_HELP }, { "plugin", required_argument, NULL, GETOPT_VAL_PLUGIN }, { "plugin-opts", required_argument, NULL, GETOPT_VAL_PLUGIN_OPTS }, + { "password", required_argument, NULL, GETOPT_VAL_PASSWORD }, + { "key", required_argument, NULL, GETOPT_VAL_KEY }, #ifdef __linux__ { "mptcp", no_argument, NULL, GETOPT_VAL_MPTCP }, #endif @@ -1401,6 +1404,9 @@ main(int argc, char **argv) mptcp = 1; LOGI("enable multipath TCP"); break; + case GETOPT_VAL_KEY: + key = optarg; + break; case GETOPT_VAL_REUSE_PORT: reuse_port = 1; break; @@ -1415,6 +1421,7 @@ main(int argc, char **argv) case 'p': server_port = optarg; break; + case GETOPT_VAL_PASSWORD: case 'k': password = optarg; break; @@ -1495,6 +1502,9 @@ main(int argc, char **argv) if (password == NULL) { password = conf->password; } + if (key == NULL) { + key = conf->key; + } if (method == NULL) { method = conf->method; } @@ -1542,7 +1552,8 @@ main(int argc, char **argv) server_host[server_num++] = NULL; } - if (server_num == 0 || server_port == NULL || password == NULL) { + if (server_num == 0 || server_port == NULL + || (password == NULL && key == NULL)) { usage(); exit(EXIT_FAILURE); } @@ -1621,7 +1632,7 @@ main(int argc, char **argv) // setup keys LOGI("initializing ciphers... %s", method); - crypto = crypto_init(password, method); + crypto = crypto_init(password, key, method); if (crypto == NULL) FATAL("failed to initialize ciphers"); diff --git a/src/stream.c b/src/stream.c index 876caa13..e3883857 100644 --- a/src/stream.c +++ b/src/stream.c @@ -598,7 +598,7 @@ stream_ctx_release(cipher_ctx_t *cipher_ctx) } cipher_t * -stream_key_init(int method, const char *pass) +stream_key_init(int method, const char *pass, const char *key) { if (method <= TABLE || method >= STREAM_CIPHER_NUM) { LOGE("cipher->key_init(): Illegal method"); @@ -623,8 +623,10 @@ stream_key_init(int method, const char *pass) FATAL("Cannot initialize cipher"); } - cipher->key_len = crypto_derive_key(cipher, pass, - cipher->key, cipher_key_size(cipher), 1); + if (key != NULL) + cipher->key_len = crypto_parse_key(key, cipher->key, cipher_key_size(cipher)); + else + cipher->key_len = crypto_derive_key(pass, cipher->key, cipher_key_size(cipher)); if (cipher->key_len == 0) { FATAL("Cannot generate key and NONCE"); @@ -640,7 +642,7 @@ stream_key_init(int method, const char *pass) } cipher_t * -stream_init(const char *pass, const char *method) +stream_init(const char *pass, const char *key, const char *method) { int m = TABLE; if (method != NULL) { @@ -657,5 +659,6 @@ stream_init(const char *pass, const char *method) LOGE("Table is deprecated"); return NULL; } - return stream_key_init(m, pass); + return stream_key_init(m, pass, key); } + diff --git a/src/stream.h b/src/stream.h index e22eee0a..92727bb0 100644 --- a/src/stream.h +++ b/src/stream.h @@ -47,6 +47,6 @@ int stream_decrypt(buffer_t *, cipher_ctx_t *, size_t); void stream_ctx_init(cipher_t *, cipher_ctx_t *, int); void stream_ctx_release(cipher_ctx_t *); -cipher_t *stream_init(const char *pass, const char *method); +cipher_t *stream_init(const char *pass, const char *key, const char *method); #endif // _STREAM_H diff --git a/src/tunnel.c b/src/tunnel.c index 8998a48e..607f251b 100644 --- a/src/tunnel.c +++ b/src/tunnel.c @@ -729,6 +729,7 @@ main(int argc, char **argv) char *local_port = NULL; char *local_addr = NULL; char *password = NULL; + char *key = NULL; char *timeout = NULL; char *method = NULL; char *pid_path = NULL; @@ -754,6 +755,8 @@ main(int argc, char **argv) { "plugin", required_argument, NULL, GETOPT_VAL_PLUGIN }, { "plugin-opts", required_argument, NULL, GETOPT_VAL_PLUGIN_OPTS }, { "reuse-port", no_argument, NULL, GETOPT_VAL_REUSE_PORT }, + { "password", required_argument, NULL, GETOPT_VAL_PASSWORD }, + { "key", required_argument, NULL, GETOPT_VAL_KEY }, { "help", no_argument, NULL, GETOPT_VAL_HELP }, { NULL, 0, NULL, 0 } }; @@ -784,6 +787,9 @@ main(int argc, char **argv) case GETOPT_VAL_PLUGIN_OPTS: plugin_opts = optarg; break; + case GETOPT_VAL_KEY: + key = optarg; + break; case GETOPT_VAL_REUSE_PORT: reuse_port = 1; break; @@ -799,6 +805,7 @@ main(int argc, char **argv) case 'l': local_port = optarg; break; + case GETOPT_VAL_PASSWORD: case 'k': password = optarg; break; @@ -891,6 +898,9 @@ main(int argc, char **argv) if (password == NULL) { password = conf->password; } + if (key == NULL) { + key = conf->key; + } if (method == NULL) { method = conf->method; } @@ -928,8 +938,8 @@ main(int argc, char **argv) #endif } - if (remote_num == 0 || remote_port == NULL || tunnel_addr_str == NULL || - local_port == NULL || password == NULL) { + if (remote_num == 0 || remote_port == NULL || tunnel_addr_str == NULL + || local_port == NULL || (password == NULL && key == NULL)) { usage(); exit(EXIT_FAILURE); } @@ -1017,7 +1027,7 @@ main(int argc, char **argv) // Setup keys LOGI("initializing ciphers... %s", method); - crypto = crypto_init(password, method); + crypto = crypto_init(password, key, method); if (crypto == NULL) FATAL("failed to initialize ciphers"); diff --git a/src/utils.c b/src/utils.c index f19eddeb..26b26418 100644 --- a/src/utils.c +++ b/src/utils.c @@ -353,6 +353,10 @@ usage() #ifdef __linux__ printf( " [--mptcp] Enable Multipath TCP on MPTCP Kernel.\n"); +#endif +#ifndef MODULE_MANAGER + printf( + " [--key ] Key of your remote server.\n"); #endif printf( " [--plugin ] Enable SIP003 plugin. (Experimental)\n");