diff --git a/src/encrypt.c b/src/encrypt.c index ce3f5cca..c709d8d5 100644 --- a/src/encrypt.c +++ b/src/encrypt.c @@ -8,6 +8,19 @@ #define OFFSET_ROL(p, o) ((uint64_t)(*(p + o)) << (8 * o)) +static char *enc_table; +static char *dec_table; +static void* supported_ciphers = { + NULL, + EVP_rc4, + EVP_aes_128_cfb, + EVP_aes_192_cfb, + EVP_aes_256_cfb, + EVP_bf_cfb, + EVP_cast5_cvb, + EVP_des_cfb +}; + static void md5(const uint8_t *text, uint8_t *digest) { md5_state_t state; md5_init(&state); @@ -15,16 +28,14 @@ static void md5(const uint8_t *text, uint8_t *digest) { md5_finish(&state, digest); } -static int random_compare(const void *_x, const void *_y) { - uint32_t i = enc_conf.ctx.table.salt; - uint64_t a = enc_conf.ctx.table.key; +static int random_compare(const void *_x, const void *_y, uint32_t i, uint64_t a) { uint8_t x = *((uint8_t *) _x); uint8_t y = *((uint8_t*) _y); return (a % (x + i) - a % (y + i)); } -static void merge(uint8_t *left, int llength, uint8_t *right, int rlength) -{ +static void merge(uint8_t *left, int llength, uint8_t *right, + int rlength, uint32_t salt, uint64_t key) { uint8_t *ltmp = (uint8_t *) malloc(llength * sizeof(uint8_t)); uint8_t *rtmp = (uint8_t *) malloc(rlength * sizeof(uint8_t)); @@ -37,7 +48,7 @@ static void merge(uint8_t *left, int llength, uint8_t *right, int rlength) memcpy(rtmp, right, rlength * sizeof(uint8_t)); while (llength > 0 && rlength > 0) { - if (random_compare(ll, rr) <= 0) { + if (random_compare(ll, rr, salt, key) <= 0) { *result = *ll; ++ll; --llength; @@ -68,8 +79,8 @@ static void merge(uint8_t *left, int llength, uint8_t *right, int rlength) free(rtmp); } -static void merge_sort(uint8_t array[], int length) -{ +static void merge_sort(uint8_t array[], int length, + uint32_t salt, uint64_t key) { uint8_t middle; uint8_t *left, *right; int llength; @@ -84,87 +95,148 @@ static void merge_sort(uint8_t array[], int length) left = array; right = array + llength; - merge_sort(left, llength); - merge_sort(right, middle); - merge(left, llength, right, middle); + merge_sort(left, llength, salt, key); + merge_sort(right, middle, salt, key); + merge(left, llength, right, middle, salt, key); } -void encrypt_ctx(char *buf, int len, struct rc4_state *ctx) { - if (ctx != NULL) { - rc4_crypt(ctx, (uint8_t*) buf, (uint8_t*) buf, len); - } else { - char *end = buf + len; - while (buf < end) { - *buf = (char)enc_conf.ctx.table.encrypt_table[(uint8_t)*buf]; - buf++; - } - } -} - -void decrypt_ctx(char *buf, int len, struct rc4_state *ctx) { - if (ctx != NULL) { - rc4_crypt(ctx, (uint8_t*) buf, (uint8_t*) buf, len); - } else { - char *end = buf + len; - while (buf < end) { - *buf = (char)enc_conf.ctx.table.decrypt_table[(uint8_t)*buf]; - buf++; - } - } -} - -void enc_ctx_init(struct rc4_state *ctx, int enc) { - uint8_t *key = enc_conf.ctx.rc4.key; - int key_len = enc_conf.ctx.rc4.key_len; - rc4_init(ctx, key, key_len); -} - -static void enc_rc4_init(const char *pass) { - enc_conf.ctx.rc4.key_len = 16; - enc_conf.ctx.rc4.key = malloc(16); - md5((const uint8_t*)pass, enc_conf.ctx.rc4.key); -} - -static void enc_table_init(const char *pass) { - uint8_t *enc_table = malloc(256); - uint8_t *dec_table = malloc(256); - uint8_t digest[16]; - uint32_t *salt = &enc_conf.ctx.table.salt; - uint64_t *key = &enc_conf.ctx.table.key; +void enc_table_init(const char *pass) { uint32_t i; + uint32_t salt; + uint64_t key = 0; + uint8_t digest[16]; + + enc_table = malloc(256); + dec_table = malloc(256); md5((const uint8_t*)pass, digest); - *key = 0; for (i = 0; i < 8; i++) { - *key += OFFSET_ROL(digest, i); + key += OFFSET_ROL(digest, i); } for(i = 0; i < 256; ++i) { enc_table[i] = i; } for(i = 1; i < 1024; ++i) { - *salt = i; - merge_sort(enc_table, 256); + salt = i; + merge_sort(enc_table, 256, salt, key); } for(i = 0; i < 256; ++i) { // gen decrypt table from encrypt table dec_table[enc_table[i]] = i; } +} - enc_conf.ctx.table.encrypt_table = enc_table; - enc_conf.ctx.table.decrypt_table = dec_table; +char* encrypt(char *plaintext, int *len, struct enc_ctx *ctx) { + if (ctx != NULL) { + /* max ciphertext len for a n bytes of plaintext is n + AES_BLOCK_SIZE + * -1 bytes */ + int c_len = *len + AES_BLOCK_SIZE; + uint8_t *ciphertext; + int iv_len = 0; + + if (ctx->method > RC4) { + iv_len += strlen(ctx->iv); + ciphertext = malloc(iv_len + c_len); + strcpy(ciphertext, ctx->iv); + ctx->method = NONE; + } else { + ciphertext = malloc(c_len); + } + + EVP_EncryptUpdate(ctx->evp, ciphertext + iv_len, &c_len, plaintext, *len); + *len = iv_len + c_len; + free(plaintext); + return ciphertext; + } else { + char *begin = plaintext; + while (plaintext < begin + *len) { + *plaintext = (char)enc_table[(uint8_t)*plaintext]; + plaintext++; + } + return begin; + } +} + +char* decrypt(char *ciphertext, int *len, struct enc_ctx *ctx) { + if (ctx != NULL) { + /* max ciphertext len for a n bytes of plaintext is n + AES_BLOCK_SIZE + * -1 bytes */ + int p_len = *len + AES_BLOCK_SIZE; + uint8_t *plaintext = malloc(p_len); + int iv_len = 0; + + if (ctx->method > RC4) { + iv_len = strlen(ctx->iv); + memcpy(ctx->iv, ciphertext, iv_len); + ctx->method = NONE; + } + + EVP_DecryptUpdate(ctx->evp, plaintext, &p_len, + (uint8_t*)(ciphertext + iv_len), *len - iv_len); + *len = p_len; + free(ciphertext); + return plaintext; + } else { + char *begin = ciphertext; + while (ciphertext < begin + *len) { + *ciphertext = (char)dec_table[(uint8_t)*ciphertext]; + ciphertext++; + } + return begin; + } } -void enc_conf_init(const char *pass, const char *method) { - enc_conf.method = TABLE; - if (method != NULL && strcmp(method, "rc4") == 0) { - enc_conf.method = RC4; +void enc_ctx_init(int method, struct enc_ctx *ctx, int enc) { + uint8_t key[EVP_MAX_KEY_LENGTH] = {0}; + uint8_t iv[EVP_MAX_IV_LENGTH] = {0}; + int key_len; + + EVP_CIPHER *cipher = (*supported_ciphers[method])(); + key_len = EVP_BytesToKey(cipher, EVP_md5(), NULL, (uint8_t *)pass, + strlen(pass), 1, key, iv); + + EVP_CIPHER_CTX_init(ctx->evp); + EVP_CipherInit_ex(ctx->evp, cipher, NULL, NULL, NULL, enc); + if (!EVP_CIPHER_CTX_set_key_length(ctx->evp, key_len)) { + EVP_CIPHER_CTX_cleanup(ctx->evp); + LOGE("Invalid key length: %d", key_len); + exit(EXIT_FAILURE); + } + EVP_CIPHER_CTX_set_padding(ctx->evp, 1); + + if (enc) { + int i; + EVP_CipherInit_ex(ctx->evp, NULL, NULL, key, iv, enc); + } + + memset(ctx->iv, 0, strlen(iv)); + for (i = 0; i < strlen(iv); i++) { + ctx->iv[i] = rand() % 256; } - if (enc_conf.method == TABLE) { + ctx->method = method; +} + +int enc_init(const char *pass, const char *method) { + if (method == NULL || strcmp(method, "table") == 0) { enc_table_init(pass); - } else if (enc_conf.method == RC4) { - enc_rc4_init(pass); + return TABLE; + } else if (strcmp(method, "aes-128-cfb") == 0) { + return AES_128_CFB; + } else if (strcmp(method, "aes-192-cfb") == 0) { + return AES_192_CFB; + } else if (strcmp(method, "aes-256-cfb") == 0) { + return AES_256_CFB; + } else if (strcmp(method, "bf-cfb") == 0) { + return BF_CFB; + } else if (strcmp(method, "cast5-cfb") == 0) { + return CAST5_CFB; + } else if (strcmp(method, "des-cfb") == 0) { + return DES_CFB; + } else if (strcmp(method, "rc4") == 0) { + return RC4; } + return TABLE; } diff --git a/src/encrypt.h b/src/encrypt.h index 6e9b0f14..dcf21f88 100644 --- a/src/encrypt.h +++ b/src/encrypt.h @@ -8,6 +8,8 @@ #include #include +#include + #ifdef HAVE_STDINT_H #include #elif HAVE_INTTYPES_H @@ -15,33 +17,28 @@ #endif #include "md5.h" -#include "rc4.h" #define BUF_SIZE 4096 -#define TABLE 0 -#define RC4 1 - -struct { +#define NONE -1 +#define TABLE 0 +#define RC4 1 +#define AES_128_CFB 2 +#define AES_192_CFB 3 +#define AES_256_CFB 4 +#define BF_CFB 5 +#define CAST5_CFB 6 +#define DES_CFB 7 + +struct enc_ctx { int method; - union { - struct { - uint8_t *encrypt_table; - uint8_t *decrypt_table; - uint32_t salt; - uint64_t key; - } table; - - struct { - uint8_t *key; - int key_len; - } rc4; - } ctx; -} enc_conf; - -void encrypt_ctx(char *buf, int len, struct rc4_state *ctx); -void decrypt_ctx(char *buf, int len, struct rc4_state *ctx); -void enc_ctx_init(struct rc4_state *ctx, int enc); -void enc_conf_init(const char *pass, const char *method); + uint8_t iv[EVP_MAX_IV_LENGTH]; + EVP_CIPHER_CTX *evp; +}; + +char* encrypt(char *buf, int len, EVP_CIPHER_CTX *ctx); +char* decrypt(char *buf, int len, EVP_CIPHER_CTX *ctx); +void enc_ctx_init(int method, struct enc_ctx *ctx, int enc); +int enc_init(const char *pass, const char *method); #endif // _ENCRYPT_H diff --git a/src/local.c b/src/local.c index 684290c8..9c027353 100644 --- a/src/local.c +++ b/src/local.c @@ -140,7 +140,7 @@ static void server_recv_cb (EV_P_ ev_io *w, int revents) { // local socks5 server if (server->stage == 5) { - encrypt_ctx(remote->buf, r, server->e_ctx); + remote->buf = encrypt(remote->buf, r, server->e_ctx); int s = send(remote->fd, remote->buf, r, 0); if(s == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { @@ -188,7 +188,7 @@ static void server_recv_cb (EV_P_ ev_io *w, int revents) { return; } - char addr_to_send[256]; + char *addr_to_send = malloc(256); uint8_t addr_len = 0; addr_to_send[addr_len++] = request->atyp; @@ -223,8 +223,10 @@ static void server_recv_cb (EV_P_ ev_io *w, int revents) { return; } - encrypt_ctx(addr_to_send, addr_len, server->e_ctx); + addr_to_send = encrypt(addr_to_send, addr_len, server->e_ctx); int s = send(remote->fd, addr_to_send, addr_len, 0); + free(addr_to_send); + if (s < addr_len) { LOGE("failed to send remote addr."); close_and_free_remote(EV_A_ remote); @@ -352,7 +354,7 @@ static void remote_recv_cb (EV_P_ ev_io *w, int revents) { } } - decrypt_ctx(server->buf, r, server->d_ctx); + server->buf = decrypt(server->buf, r, server->d_ctx); int s = send(server->fd, server->buf, r, 0); if (s == -1) { @@ -445,6 +447,7 @@ static void remote_send_cb (EV_P_ ev_io *w, int revents) { struct remote* new_remote(int fd, int timeout) { struct remote *remote; remote = malloc(sizeof(struct remote)); + remote->buf = malloc(256); remote->recv_ctx = malloc(sizeof(struct remote_ctx)); remote->send_ctx = malloc(sizeof(struct remote_ctx)); remote->fd = fd; @@ -465,6 +468,7 @@ void free_remote(struct remote *remote) { if (remote->server != NULL) { remote->server->remote = NULL; } + free(remote->buf); free(remote->recv_ctx); free(remote->send_ctx); free(remote); @@ -481,9 +485,10 @@ void close_and_free_remote(EV_P_ struct remote *remote) { } } -struct server* new_server(int fd) { +struct server* new_server(int fd, int method) { struct server *server; server = malloc(sizeof(struct server)); + server->buf = malloc(256); server->recv_ctx = malloc(sizeof(struct server_ctx)); server->send_ctx = malloc(sizeof(struct server_ctx)); server->fd = fd; @@ -494,11 +499,11 @@ struct server* new_server(int fd) { server->send_ctx->server = server; server->send_ctx->connected = 0; server->stage = 0; - if (enc_conf.method == RC4) { - server->e_ctx = malloc(sizeof(struct rc4_state)); - server->d_ctx = malloc(sizeof(struct rc4_state)); - enc_ctx_init(server->e_ctx, 1); - enc_ctx_init(server->d_ctx, 0); + if (method) { + server->e_ctx = malloc(sizeof(struct enc_ctx)); + server->d_ctx = malloc(sizeof(struct enc_ctx)); + enc_ctx_init(method, server->e_ctx, 1); + enc_ctx_init(method, server->d_ctx, 0); } else { server->e_ctx = NULL; server->d_ctx = NULL; @@ -513,10 +518,15 @@ void free_server(struct server *server) { if (server->remote != NULL) { server->remote->server = NULL; } - if (enc_conf.method == RC4) { + if (server->e_ctx != NULL) { + EVP_CIPHER_CTX_cleanup(server->e_ctx); free(server->e_ctx); + } + if (server->d_ctx != NULL) { + EVP_CIPHER_CTX_cleanup(server->d_ctx); free(server->d_ctx); } + free(server->buf); free(server->recv_ctx); free(server->send_ctx); free(server); @@ -577,7 +587,7 @@ static void accept_cb (EV_P_ ev_io *w, int revents) { if (listener->iface) setinterface(sockfd, listener->iface); #endif - struct server *server = new_server(serverfd); + struct server *server = new_server(serverfd, listener->method); struct remote *remote = new_remote(sockfd, listener->timeout); server->remote = remote; remote->server = server; @@ -676,7 +686,7 @@ int main (int argc, char **argv) { // Setup keys LOGD("calculating ciphers..."); - enc_conf_init(password, method); + int m = enc_init(password, method); // Setup socket int listenfd; @@ -702,6 +712,7 @@ int main (int argc, char **argv) { listen_ctx.timeout = atoi(timeout); listen_ctx.fd = listenfd; listen_ctx.iface = iface; + listen_ctx.method = m; struct ev_loop *loop = ev_default_loop(0); if (!loop) { diff --git a/src/local.h b/src/local.h index daf7b482..6df50082 100644 --- a/src/local.h +++ b/src/local.h @@ -11,6 +11,7 @@ struct listen_ctx { int remote_num; char *remote_port; char *iface; + int method; int timeout; int fd; struct sockaddr sock; @@ -24,12 +25,12 @@ struct server_ctx { struct server { int fd; - char buf[BUF_SIZE]; // server send from, remote recv into + char *buf; // server send from, remote recv into char stage; int buf_len; int buf_idx; - struct rc4_state *e_ctx; - struct rc4_state *d_ctx; + struct enc_ctx *e_ctx; + struct enc_ctx *d_ctx; struct server_ctx *recv_ctx; struct server_ctx *send_ctx; struct remote *remote; @@ -61,7 +62,7 @@ static void remote_send_cb (EV_P_ ev_io *w, int revents); struct remote* new_remote(int fd, int timeout); void free_remote(struct remote *remote); void close_and_free_remote(EV_P_ struct remote *remote); -struct server* new_server(int fd); +struct server* new_server(int fd, int method); void free_server(struct server *server); void close_and_free_server(EV_P_ struct server *server); diff --git a/src/rc4.c b/src/rc4.c deleted file mode 100644 index 1759d1fe..00000000 --- a/src/rc4.c +++ /dev/null @@ -1,103 +0,0 @@ - -/* - * rc4.c - * - * Copyright (c) 1996-2000 Whistle Communications, Inc. - * All rights reserved. - * - * Subject to the following obligations and disclaimer of warranty, use and - * redistribution of this software, in source or object code forms, with or - * without modifications are expressly permitted by Whistle Communications; - * provided, however, that: - * 1. Any and all reproductions of the source or object code must include the - * copyright notice above and the following disclaimer of warranties; and - * 2. No rights are granted, in any manner or form, to use Whistle - * Communications, Inc. trademarks, including the mark "WHISTLE - * COMMUNICATIONS" on advertising, endorsements, or otherwise except as - * such appears in the above copyright notice or in the software. - * - * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND - * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO - * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, - * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. - * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY - * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS - * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. - * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES - * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING - * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * $FreeBSD: src/sys/crypto/rc4/rc4.c,v 1.2.2.1 2000/04/18 04:48:31 archie Exp $ - */ -#include -#include "rc4.h" - -static inline void -swap_bytes(u_char *a, u_char *b) -{ - u_char temp; - - temp = *a; - *a = *b; - *b = temp; -} - -/* - * Initialize an RC4 state buffer using the supplied key, - * which can have arbitrary length. - */ -void -rc4_init(struct rc4_state *const state, const u_char *key, int keylen) -{ - u_char j; - int i; - - /* Initialize state with identity permutation */ - for (i = 0; i < 256; i++) - state->perm[i] = (u_char)i; - state->index1 = 0; - state->index2 = 0; - - /* Randomize the permutation using key data */ - for (j = i = 0; i < 256; i++) { - j += state->perm[i] + key[i % keylen]; - swap_bytes(&state->perm[i], &state->perm[j]); - } -} - -/* - * Encrypt some data using the supplied RC4 state buffer. - * The input and output buffers may be the same buffer. - * Since RC4 is a stream cypher, this function is used - * for both encryption and decryption. - */ -void -rc4_crypt(struct rc4_state *const state, - const u_char *inbuf, u_char *outbuf, int buflen) -{ - int i; - u_char j; - - for (i = 0; i < buflen; i++) { - - /* Update modification indicies */ - state->index1++; - state->index2 += state->perm[state->index1]; - - /* Modify permutation */ - swap_bytes(&state->perm[state->index1], - &state->perm[state->index2]); - - /* Encrypt/decrypt next byte */ - j = state->perm[state->index1] + state->perm[state->index2]; - outbuf[i] = inbuf[i] ^ state->perm[j]; - } -} - diff --git a/src/rc4.h b/src/rc4.h deleted file mode 100644 index 40c6b46e..00000000 --- a/src/rc4.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * rc4.h - * - * Copyright (c) 1996-2000 Whistle Communications, Inc. - * All rights reserved. - * - * Subject to the following obligations and disclaimer of warranty, use and - * redistribution of this software, in source or object code forms, with or - * without modifications are expressly permitted by Whistle Communications; - * provided, however, that: - * 1. Any and all reproductions of the source or object code must include the - * copyright notice above and the following disclaimer of warranties; and - * 2. No rights are granted, in any manner or form, to use Whistle - * Communications, Inc. trademarks, including the mark "WHISTLE - * COMMUNICATIONS" on advertising, endorsements, or otherwise except as - * such appears in the above copyright notice or in the software. - * - * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND - * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO - * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, - * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. - * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY - * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS - * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. - * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES - * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING - * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, - * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * $FreeBSD: src/sys/crypto/rc4/rc4.h,v 1.2.2.1 2000/04/18 04:48:32 archie Exp $ - */ - -#ifndef RC4_H_ -#define RC4_H_ - -typedef uint8_t u_char; - -struct rc4_state { - u_char perm[256]; - u_char index1; - u_char index2; -}; - -void rc4_init(struct rc4_state *state, const u_char *key, int keylen); -void rc4_crypt(struct rc4_state *state, - const u_char *inbuf, u_char *outbuf, int buflen); - -#endif -