diff --git a/README.md b/README.md index 873f77a..579705f 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,68 @@ UDTCAT ====== -netcat-like utility using UDP-Based Data Transfer +UDTCAT is a UDT data transfer device based off of the functionality of netcat. + +CONTENT +------- +./src: UDTCAT source code + +./udt: UDT source code, documentation and license + + +TO MAKE +------- + make -e os=XXX arch=YYY + +XXX: [LINUX(default), BSD, OSX] +YYY: [IA32(default), POWERPC, IA64, AMD64] + +### Dependencies: +OpenSSL (libssl and libcrypto) + +UDTCAT has only been tested for Linux. + + +USAGE +------ + +UDTCAT follows the same model as netcat. The server side establishes a listener, and awaits an incoming connection. The client side connects to an established server or times out. Encryption is off by default. The encrypted option uses a multithreaded version of OpenSSL with aes-128. + +### Basic usage: + +Server side: + uc [udtcat options] -l port + +Client side: + uc [udtcat options] host port + +#### UDTCAT Options: + + -l start a server + -n n_crypto_threads set number of encryption threads per send/recv thread to n_crypto_threads + -f path path to key file + -v verbose + +### Basic exmple (unencrypted) + +Client side: + + uc localhost 9000 < source/file + +Server side: + + uc -l 9000 > output/file + +### Basic exmple (encrypted) + +Client side: + + uc -n=4 -p PASSword localhost 9000 < source/file + +Server side: + + uc -n=4 -f file/contains/PASSword -l 9000 > output/file + +This examples creates a connection to trasfer "source/file" to "output/file" over an encrypted stream on port 9000 which uses 4 threads to encrypt/decrypt each block. The password used as a key for OpenSSL is "PASSword" + + diff --git a/src/crypto.cpp b/src/crypto.cpp index 6a556a9..e007328 100644 --- a/src/crypto.cpp +++ b/src/crypto.cpp @@ -208,7 +208,7 @@ int join_all_encryption_threads(crypto *c){ return 0; } - for (int i = 0; i < N_CRYPTO_THREADS; i++){ + for (int i = 0; i < c->get_num_crypto_threads(); i++){ c->lock_data(i); c->unlock_data(i); } diff --git a/src/crypto.h b/src/crypto.h index a1ca161..6c45a40 100644 --- a/src/crypto.h +++ b/src/crypto.h @@ -18,7 +18,8 @@ and limitations under the License. #ifndef CRYPTO_H #define CRYPTO_H -#define N_CRYPTO_THREADS 8 +#define MAX_CRYPTO_THREADS 32 +#define USE_CRYPTO 1 #define PASSPHRASE_SIZE 32 #define HEX_PASSPHRASE_SIZE 64 @@ -48,6 +49,8 @@ int THREAD_setup(void); int THREAD_cleanup(void); void *enrypt_threaded(void* _args); + + using namespace std; typedef unsigned char uchar; @@ -67,18 +70,20 @@ void *crypto_update_thread(void* _args); class crypto { - private: + private: //BF_KEY key; unsigned char ivec[ 1024 ]; int direction; - pthread_mutex_t c_lock[N_CRYPTO_THREADS]; - pthread_mutex_t thread_ready[N_CRYPTO_THREADS]; + pthread_mutex_t c_lock[MAX_CRYPTO_THREADS]; + pthread_mutex_t thread_ready[MAX_CRYPTO_THREADS]; pthread_mutex_t id_lock; int passphrase_size; int hex_passphrase_size; + int N_CRYPTO_THREADS; + int thread_id; @@ -88,17 +93,19 @@ class crypto // EVP stuff - EVP_CIPHER_CTX ctx[N_CRYPTO_THREADS]; + EVP_CIPHER_CTX ctx[MAX_CRYPTO_THREADS]; - e_thread_args e_args[N_CRYPTO_THREADS]; + e_thread_args e_args[MAX_CRYPTO_THREADS]; - pthread_t threads[N_CRYPTO_THREADS]; + pthread_t threads[MAX_CRYPTO_THREADS]; - crypto(int direc, int len, unsigned char* password, char *encryption_type) + crypto(int direc, int len, unsigned char* password, char *encryption_type, int n_threads) { - + + N_CRYPTO_THREADS = n_threads; + THREAD_setup(); //free_key( password ); can't free here because is reused by threads const EVP_CIPHER *cipher; @@ -172,7 +179,7 @@ class crypto pthread_mutex_init(&thread_ready[i], NULL); pthread_mutex_lock(&thread_ready[i]); } - + // ----------- [ Initialize and set thread detached attribute pthread_attr_t attr; pthread_attr_init(&attr); @@ -199,6 +206,10 @@ class crypto } + int get_num_crypto_threads(){ + return N_CRYPTO_THREADS; + } + int get_thread_id(){ pthread_mutex_lock(&id_lock); int id = thread_id; diff --git a/src/udtcat.cpp b/src/udtcat.cpp index 026ead5..cb4b5ed 100644 --- a/src/udtcat.cpp +++ b/src/udtcat.cpp @@ -32,12 +32,8 @@ using std::endl; void usage(){ fprintf(stderr, "usage: udtcat [udtcat options] host port\n"); fprintf(stderr, "options:\n"); - fprintf(stderr, "\t\t%s %s\t%s\n", "-l", "\t", "server"); - fprintf(stderr, "\t\t%s %s\t%s\n", "-n", "\t", "use encryption"); - fprintf(stderr, "\t\t%s %s\t%s\n", "-p", "password", "password string"); - fprintf(stderr, "\t\t%s %s\t%s\n", "-f", "path\t", "path to password"); - fprintf(stderr, "\t\t%s %s\t%s\n", "-v", "\t", "verbose"); // fprintf(stderr, "\t\t%s %s\t%s\n", "", "", ""); + exit(1); } @@ -51,6 +47,7 @@ void initialize_thread_args(thread_args *args){ args->mss = 8400; args->use_crypto = 0; args->verbose = 0; + args->n_crypto_threads = 1; } int main(int argc, char *argv[]){ @@ -65,9 +62,10 @@ int main(int argc, char *argv[]){ int verbose = 0; char* path_to_key = NULL; char* key = NULL; + int n_crypto_threads = 1; // ----------- [ Read in options - while ((opt = getopt (argc, argv, "hvnlp:f:")) != -1){ + while ((opt = getopt (argc, argv, "hvn:lp:f:")) != -1){ switch (opt){ case 'l': @@ -80,14 +78,19 @@ int main(int argc, char *argv[]){ case 'n': args.use_crypto = 1; - use_crypto = 1; + use_crypto = 1; + n_crypto_threads = atoi(optarg); break; case 'p': + args.use_crypto = 1; + use_crypto = 1; key = strdup(optarg); break; case 'f': + args.use_crypto = 1; + use_crypto = 1; path_to_key = strdup(optarg); break; @@ -123,9 +126,9 @@ int main(int argc, char *argv[]){ } - if (!use_crypto && key){ - fprintf(stderr, "warning: You've specified a key, but you don't have encryption turned on.\nProceeding without encryption.\n"); - } + // if (!use_crypto && key){ + // fprintf(stderr, "warning: You've specified a key, but you don't have encryption turned on.\nProceeding without encryption.\n"); + // } if (use_crypto && !key){ fprintf(stderr, "Please either: \n (1) %s\n (2) %s\n (3) %s\n", @@ -157,11 +160,13 @@ int main(int argc, char *argv[]){ if (use_crypto){ char* cipher = (char*) "aes-128"; - crypto enc(EVP_ENCRYPT, PASSPHRASE_SIZE, (unsigned char*)key, cipher); - crypto dec(EVP_DECRYPT, PASSPHRASE_SIZE, (unsigned char*)key, cipher); + crypto enc(EVP_ENCRYPT, PASSPHRASE_SIZE, (unsigned char*)key, cipher, n_crypto_threads); + crypto dec(EVP_DECRYPT, PASSPHRASE_SIZE, (unsigned char*)key, cipher, n_crypto_threads); args.enc = &enc; args.dec = &dec; + args.n_crypto_threads = n_crypto_threads; + } else { args.enc = NULL; diff --git a/src/udtcat.h b/src/udtcat.h index dc4df12..72914ec 100644 --- a/src/udtcat.h +++ b/src/udtcat.h @@ -37,7 +37,8 @@ typedef struct rs_args{ crypto *c; int use_crypto; int verbose; -} recv_args; + int n_crypto_threads; +} rs_args; typedef struct thread_args{ crypto *enc; @@ -51,6 +52,7 @@ typedef struct thread_args{ int mss; int use_crypto; int verbose; + int n_crypto_threads; } thread_args; void* send_buf_threaded(void*_args); diff --git a/src/udtcat_client.cpp b/src/udtcat_client.cpp index 901b42b..42f9b90 100644 --- a/src/udtcat_client.cpp +++ b/src/udtcat_client.cpp @@ -111,6 +111,7 @@ int run_client(thread_args *args) rcvargs.usocket = new UDTSOCKET(client); rcvargs.use_crypto = args->use_crypto; rcvargs.verbose = args->verbose; + rcvargs.n_crypto_threads = args->n_crypto_threads; rcvargs.c = args->dec; pthread_create(&rcvthread, NULL, recvdata, &rcvargs); @@ -125,6 +126,7 @@ int run_client(thread_args *args) send_args.usocket = new UDTSOCKET(client); send_args.use_crypto = args->use_crypto; send_args.verbose = args->verbose; + send_args.n_crypto_threads = args->n_crypto_threads; send_args.c = args->enc; // freeaddrinfo(peer); diff --git a/src/udtcat_server.cpp b/src/udtcat_server.cpp index 0cb697c..a28cfd2 100644 --- a/src/udtcat_server.cpp +++ b/src/udtcat_server.cpp @@ -133,6 +133,7 @@ int run_server(thread_args *args){ rcvargs.usocket = new UDTSOCKET(recver); rcvargs.use_crypto = args->use_crypto; rcvargs.verbose = args->verbose; + rcvargs.n_crypto_threads = args->n_crypto_threads; rcvargs.c = args->dec; pthread_create(&rcvthread, NULL, recvdata, &rcvargs); @@ -145,6 +146,7 @@ int run_server(thread_args *args){ send_args.usocket = new UDTSOCKET(recver); send_args.use_crypto = args->use_crypto; send_args.verbose = args->verbose; + send_args.n_crypto_threads = args->n_crypto_threads; send_args.c = args->enc; pthread_create(&sndthread, NULL, senddata, &send_args); diff --git a/src/udtcat_threads.cpp b/src/udtcat_threads.cpp index cb17795..06a05c3 100644 --- a/src/udtcat_threads.cpp +++ b/src/udtcat_threads.cpp @@ -51,11 +51,98 @@ void print_bytes(const void *object, size_t size) fprintf(stderr, "]\n"); } +void send_full(UDTSOCKET sock, char* buffer, int len){ + + int sent = 0; + int rs = 0; + while (sent < len){ + rs = UDT::send(sock, buffer+sent, len-sent, 0); + if (UDT::ERROR == rs) { + if (UDT::getlasterror().getErrorCode() != ECONNLOST) + cerr << "recv:" << UDT::getlasterror().getErrorMessage() << + "send_full: Unable to send data." << endl; + exit(1); + } + sent += rs; + } + + +} + +void recv_full(UDTSOCKET sock, char* buffer, int len){ + + int recvd = 0; + int rs = 0; + while (recvd < len){ + rs = UDT::recv(sock, buffer+recvd, len-recvd, 0); + if (UDT::ERROR == rs) { + if (UDT::getlasterror().getErrorCode() != ECONNLOST) + cerr << "recv:" << UDT::getlasterror().getErrorMessage() << + "send_full: Unable to send data." << endl; + exit(1); + } + recvd += rs; + } + + +} + +const int KEY_LEN = 1026; + +void auth_peer(rs_args* args){ + + + char key[KEY_LEN]; + char signed_key[KEY_LEN]; + + memset(key, 1, KEY_LEN); + + send_full(*args->usocket, key, KEY_LEN); + sleep(.5); + recv_full(*args->usocket, signed_key, KEY_LEN); + + fprintf(stderr, "key: "); print_bytes(key, 16); + fprintf(stderr, "signed_key: "); print_bytes(signed_key, 16); + + int crypt_len = KEY_LEN/4; + for (int i = 0; i < crypt_len; i += crypt_len) + pass_to_enc_thread(signed_key+i, signed_key+i, crypt_len, args->c); + join_all_encryption_threads(args->c); + + if (memcmp(key, signed_key, KEY_LEN)){ + fprintf(stderr, "Authorization failed\n"); + exit(1); + + } + +} + + +void sign_auth(rs_args* args){ + + char key[KEY_LEN]; + + recv_full(*args->usocket, key, KEY_LEN); + + fprintf(stderr, "signing: "); print_bytes(key, 16); + + int crypt_len = KEY_LEN/4; + for (int i = 0; i < crypt_len; i += crypt_len) + pass_to_enc_thread(key+i, key+i, crypt_len, args->c); + + join_all_encryption_threads(args->c); + + fprintf(stderr, "signed: "); print_bytes(key, 16); + + send_full(*args->usocket, key, KEY_LEN); + +} + void* recvdata(void * _args) { - rs_args * args = (recv_args*)_args; + rs_args * args = (rs_args*)_args; if (args->verbose) fprintf(stderr, "[recv thread] Initializing receive thread...\n"); @@ -65,7 +152,7 @@ void* recvdata(void * _args) UDTSOCKET recver = *args->usocket; - int crypto_buff_len = BUFF_SIZE / N_CRYPTO_THREADS; + int crypto_buff_len = BUFF_SIZE / args->n_crypto_threads; int buffer_cursor; char* indata = (char*) malloc(BUFF_SIZE*sizeof(char)); @@ -74,38 +161,40 @@ void* recvdata(void * _args) exit(EXIT_FAILURE); } - if (args->verbose) - fprintf(stderr, "[recv thread] Checking encryption...\n"); - - long remote_ssl_version = 0; - int rs = UDT::recv(recver, (char*)&remote_ssl_version, sizeof(long), 0); - - if (UDT::ERROR == rs) { - if (UDT::getlasterror().getErrorCode() != ECONNLOST) - cerr << "recv:" << UDT::getlasterror().getErrorMessage() << - "Unable to determine remote crypto method" << endl; - exit(1); - } - - if (args->use_crypto){ - if (remote_ssl_version == 0){ - cerr << "recv: Encryption mismatch: local[None] to remote[OpenSSL]" << endl; - UDT::close(recver); - exit(1); - } - - if (remote_ssl_version != OPENSSL_VERSION_NUMBER){ - // versions don't match - } - - } else { - if (remote_ssl_version != 0) { - cerr << "recv: Encryption mismatch: local[OpenSSL] to remote[None]" << endl; - write(fileno(stderr), &remote_ssl_version, sizeof(long)); - UDT::close(recver); - exit(1); - } - } + auth_peer(args); + + // if (args->verbose) + // fprintf(stderr, "[recv thread] Checking encryption...\n"); + + // long remote_ssl_version = 0; + // int rs = UDT::recv(recver, (char*)&remote_ssl_version, sizeof(long), 0); + + // if (UDT::ERROR == rs) { + // if (UDT::getlasterror().getErrorCode() != ECONNLOST) + // cerr << "recv:" << UDT::getlasterror().getErrorMessage() << + // "Unable to determine remote crypto method" << endl; + // exit(1); + // } + + // if (args->use_crypto){ + // if (remote_ssl_version == 0){ + // cerr << "recv: Encryption mismatch: local[None] to remote[OpenSSL]" << endl; + // UDT::close(recver); + // exit(1); + // } + + // if (remote_ssl_version != OPENSSL_VERSION_NUMBER){ + // // versions don't match + // } + + // } else { + // if (remote_ssl_version != 0) { + // cerr << "recv: Encryption mismatch: local[OpenSSL] to remote[None]" << endl; + // write(fileno(stderr), &remote_ssl_version, sizeof(long)); + // UDT::close(recver); + // exit(1); + // } + // } READ_IN = 1; @@ -215,7 +304,6 @@ void* recvdata(void * _args) void* senddata(void* _args) { - rs_args * args = (rs_args*) _args; if (args->verbose) @@ -227,7 +315,7 @@ void* senddata(void* _args) fprintf(stderr, "[send thread] Send encryption is on.\n"); char* outdata = (char*)malloc(BUFF_SIZE*sizeof(char)); - int crypto_buff_len = BUFF_SIZE / N_CRYPTO_THREADS; + int crypto_buff_len = BUFF_SIZE / args->n_crypto_threads; int offset = sizeof(int)/sizeof(char); int bytes_read; @@ -235,17 +323,20 @@ void* senddata(void* _args) if (args->verbose) fprintf(stderr, "[send thread] Sending encryption status...\n"); - long local_openssl_version; - if (args->use_crypto) - local_openssl_version = OPENSSL_VERSION_NUMBER; - else - local_openssl_version = 0; + sign_auth(args); - if (UDT::send(client, (char*)&local_openssl_version, sizeof(long), 0) < 0){ - cerr << "send:" << UDT::getlasterror().getErrorMessage() << endl; - UDT::close(client); - exit(1); - } + // long local_openssl_version; + // if (args->use_crypto) + // local_openssl_version = OPENSSL_VERSION_NUMBER; + // else + // local_openssl_version = 0; + + + // if (UDT::send(client, (char*)&local_openssl_version, sizeof(long), 0) < 0){ + // // cerr << "send:" << UDT::getlasterror().getErrorMessage() << endl; + // // UDT::close(client); + // // exit(1); + // } while (!READ_IN){