From c99a31e5db124d681326d86f7aa9220de8778306 Mon Sep 17 00:00:00 2001 From: flandre scarlet Date: Sun, 13 May 2018 21:20:39 +0100 Subject: [PATCH] Initial Commit --- .gitignore | 3 + INSTALL | 9 + Makefile | 44 +++ VERSION | 1 + include/enet.h | 134 +++++++ include/internal/crc.h | 11 + include/internal/errors.h | 11 + include/internal/smem.h | 15 + src/crc.c | 52 +++ src/enet.c | 724 ++++++++++++++++++++++++++++++++++++++ src/errors.c | 93 +++++ src/smem.c | 68 ++++ src/test/main.c | 386 ++++++++++++++++++++ 13 files changed, 1551 insertions(+) create mode 100644 .gitignore create mode 100644 INSTALL create mode 100644 Makefile create mode 100644 VERSION create mode 100644 include/enet.h create mode 100644 include/internal/crc.h create mode 100644 include/internal/errors.h create mode 100644 include/internal/smem.h create mode 100644 src/crc.c create mode 100644 src/enet.c create mode 100644 src/errors.c create mode 100644 src/smem.c create mode 100644 src/test/main.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b415e8f --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +maketar +other/ +*~ diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..d5d9422 --- /dev/null +++ b/INSTALL @@ -0,0 +1,9 @@ +To install run: + make clean + make libenet + sudo make install + +To uninstall run: + sudo make uninstall + +Libraries (.so and .a) are installed to `/usr/local/lib'. Header is installed to `/usr/local/include'. The shared library is then symlinked to `/usr/lib/libenet.so' and the header is symlinked to `/usr/include/enet.h'. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ff4ecad --- /dev/null +++ b/Makefile @@ -0,0 +1,44 @@ +SOURCE:= src/*.c +SOURCE_TEST:= src/test/*.c +INCLUDE:= include +VERSION:=`cat VERSION` +CFLAGS:= -Wall -pedantic -D__VERSION=$(VERSION) +LFLAGS:= -lcrypto -lenet -lz -lm -lpthread +OBJ:= obj +BUILD:= build +TEST_OUTPUT:= ./test-out + +all: clean libenet test + +clean: + rm -f $(OBJ)/*.o + rm -f $(BUILD)/* + rm -f $(TEST_OUTPUT)/* + +libenet: + gcc -c $(SOURCE) -I$(INCLUDE)/ $(CFLAGS) -fpic + mv *.o $(OBJ)/ + gcc -shared -o $(BUILD)/$@-$(VERSION).so $(OBJ)/*.o + ar rvs $(BUILD)/$@-$(VERSION).a $(OBJ)/*.o + ln -sf `pwd`/$(BUILD)/$@-$(VERSION).so $(BUILD)/$@.so + +test: + gcc $(SOURCE_TEST) -I$(INCLUDE)/ $(CFLAGS) -o $(BUILD)/$@ -L$(BUILD)/ $(LFLAGS) + LD_LIBRARY_PATH=$(BUILD)/ $(BUILD)/$@ + mv cli_*.txt $(TEST_OUTPUT)/ + mv srv_*.txt $(TEST_OUTPUT)/ + +install: + cp $(BUILD)/libenet-$(VERSION).a /usr/local/lib/ + cp $(BUILD)/libenet-$(VERSION).so /usr/local/lib/ + cp $(INCLUDE)/*.h /usr/local/include + ln -sf /usr/local/lib/libenet-$(VERSION).so /usr/lib/libenet.so + ln -sf /usr/local/include/enet.h /usr/include/enet.h + +uninstall: + rm -f /usr/local/lib/libenet* + rm /usr/local/include/enet.h + + rm -f /usr/lib/libenet*.so + rm /usr/include/enet.h + diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..49d5957 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +0.1 diff --git a/include/enet.h b/include/enet.h new file mode 100644 index 0000000..07f0e65 --- /dev/null +++ b/include/enet.h @@ -0,0 +1,134 @@ +#ifndef _ENET_H +#define _ENET_H +#include +#include +#include +#include + +#define _EN_CUSTOM_CRC //internal macro used for building. If this is off you'll need to link with -lz as well, and there may be compatability issues. + +#define EN_CLOSE_KEEPALIVE 1 /* Keep socket connection alive */ +#define EN_CLOSE_KEEPRSA 2 /* Keep RSA object alive */ + +#define EN_RSA_KEYSIZE 1024 +#define EN_RSA_EXP 0x010001 + +#define EN_RSAP_MODSIZE 128 +#define EN_RSAP_EXPSIZE 3 + +#define EN_AESP_KEYSIZE 32 +#define EN_AESP_IVSIZE 16 + +#define EN_SUCCESS 0 +#define EN_FAILURE 1 + +#define EN_CRC32_SEED 0xffffffffu + +#define EN_READ 1 /* Controls en_read() calls (pass to en_set()) */ +#define EN_WRITE 2 /* Controls en_write() calls (pass to en_set()) */ + +#define ENE_SREAD_ERROR (1<<8) + +#define ENE_SREAD_INCORRECT_SIZE (ENE_SREAD_ERROR|(1<<0)) +#define ENE_SREAD_INVALID_CHECKSUM (ENE_SREAD_ERROR|(1<<1)) +#define ENE_SREAD_SSL_FAILURE (ENE_SREAD_ERROR|(1<<2)) +#define ENE_SREAD_AES_FAILURE (ENE_SREAD_ERROR|(1<<3)) +#define ENE_SREAD_ALREADY_AQUIRED (ENE_SREAD_ERROR|(1<<4)) + +#define ENE_RSAE_ERROR (1<<9) + +#define ENE_RSAE_INCORRECT_SIZE (ENE_RSAE_ERROR|(1<<0)) +#define ENE_RSAE_INVALID_CHECKSUM (ENE_RSAE_ERROR|(1<<1)) +#define ENE_RSAE_WRITE_FAIL (ENE_RSAE_ERROR|(1<<2)) + +#define ENE_SET_ERROR (1<<10) + +#define ENE_SET_UNKNOWN_FLAG (ENE_SET_ERROR|(1<<0)) + +#define ENE_SWRITE_ERROR (1<<11) + +#define ENE_SWRITE_SSL_FAILURE (ENE_SWRITE_ERROR|(1<<0)) +#define ENE_SWRITE_AES_FAILURE (ENE_SWRITE_ERROR|(1<<1)) +#define ENE_SWRITE_KEYGEN_FAILURE (ENE_SWRITE_ERROR|(1<<2)) +#define ENE_SWRITE_ALREADY_AQUIRED (ENE_SWRITE_ERROR|(1<<3)) + +#define ENE_USREAD_ERROR (1<<12) + +#define ENE_USREAD_NOT_AQUIRED (ENE_USREAD_ERROR|(1<<0)) + +#define ENE_USWRITE_ERROR (1<<13) + +#define ENE_USWRITE_NOT_AQUIRED (ENE_USWRITE_ERROR|(1<<0)) + +#define ENE_WRITE_ERROR (1<<14) + +#define ENE_WRITE_AES_RELOAD_FAIL (ENE_WRITE_ERROR|(1<<0)) +#define ENE_WRITE_AES_UPDATE_FAIL (ENE_WRITE_ERROR|(1<<1)) +#define ENE_WRITE_AES_FINAL_FAIL (ENE_WRITE_ERROR|(1<<2)) +#define ENE_WRITE_FAIL (ENE_WRITE_ERROR|(1<<3)) + +#define ENE_READ_ERROR (1<<15) + +#define ENE_READ_AES_RELOAD_FAIL (ENE_READ_ERROR|(1<<0)) +#define ENE_READ_AES_UPDATE_FAIL (ENE_READ_ERROR|(1<<1)) +#define ENE_READ_AES_FINAL_FAIL (ENE_READ_ERROR|(1<<2)) +#define ENE_READ_INCORRECT_SIZE (ENE_READ_ERROR|(1<<3)) +#define ENE_READ_TIMEOUT (ENE_READ_ERROR|(1<<4)) + +#define ENE_FATAL_ERROR (1<<16) +#define ENE_FATAL_HEAP_CORRUPTION (ENE_FATAL_ERROR|(1<<0)) + + +#define EN_SOCKFLAG_LOG (1<<0) /* Log all reads and writes (can be accessed with en_log()) */ +#define EN_SOCKFLAG_NOCHECKSUM (1<<1) /* Do not check data integrity */ +#define EN_SOCKFLAG_FORCEBLOCK (1<<2) /* Force reads to block until all data has been read or a timeout is reached (default 0: no timeout) */ +#define EN_SOCKFLAG_NO_HTON (1<<3) /* Do not swap byte orders */ + +#define en_addflag(sock, f) en_setflags(sock, en_getflags(sock)|f) + +typedef struct esock_t* esock_t; + +struct en_rsa_pub { + unsigned char mod[EN_RSAP_MODSIZE]; + unsigned char exp[EN_RSAP_EXPSIZE]; +}; + +struct en_aes_key { + unsigned char key[EN_AESP_KEYSIZE]; + unsigned char iv[EN_AESP_IVSIZE]; +}; + +/*** API FUNCTIONS *** + * Most int functions return EN_SUCCESS on success and EN_FAILURE on failure unless otherwise noted. + * Error reporting ***should*** be thread-safe, although I haven't tested it (subsequent calls to en_error() on the same socket will rewrite the internal buffer and could give incorrect results in a race condition) +***/ + +esock_t en_create_socket(int con, RSA *rsa); /* Create new encrypted socked from socket `con' and RSA `rsa'. If `rsa' is NULL, a new key will be generated */ +void en_close(esock_t s, int flags); /* Close and release all reources used by `s', with possible options EN_CLOSE_*. This will also free any cipher contexts that are still allocated. */ +int en_exchange(esock_t sock); /* Exchange RSA keys with remote host */ +int en_set(esock_t sock, int flag, int on); /* Set EN_READ and/or EN_WRITE either enabled (1) or disabled (0) */ +int en_get(esock_t sock, int flag); /* Check if EN_READ and/or EN_WRITE is set to encrypt */ +ssize_t en_write(esock_t sock, void* buf, size_t count); /* Write `count' no. of bytes of `buf' to `sock'. Returns >0 on success. */ +ssize_t en_read(esock_t sock, void* buf, size_t count); /* Read `count' no. of bytes from `sock' to `buf'. Returns >0 on success. */ +void en_aeskeys(esock_t sock, struct en_aes_key* write, struct en_aes_key* read); /* Get current AES keys used. This will likely segfault if they are not set, so check that yourself (maybe I should fix this?). NULL arguments are ignored. */ +void en_get_aes_read_key(esock_t sock, struct en_aes_key* key); /* Same as en_aeskeys(sock,NULL,key) */ +void en_get_aes_write_key(esock_t sock, struct en_aes_key* key); /* Same as en_aeskeys(sock,key,NULL) */ +const char* en_error(esock_t sock); /* Get last error string reported to `sock'. The pointer is to an internal buffer that may change whenever this function is called */ +RSA* en_localRSA(esock_t sock); /* Return local RSA object */ +RSA* en_remoteRSA(esock_t sock); /* Return remote RSA object */ +EVP_CIPHER_CTX* en_writeAES(esock_t sock); /* Return cipher context for write AES (NULL if not set) */ +EVP_CIPHER_CTX* en_readAES(esock_t sock); /* Return cipher context for read AES (NULL if not set) */ +void en_publickeys(esock_t sock, struct en_rsa_pub *local, struct en_rsa_pub *remote); /* Get current RSA public keys used. This will likely segfault if you have not exchagend RSA keys with remote host. */ +void en_get_rsa_local_publickey(esock_t sock, struct en_rsa_pub* local); /* Same as en_publickeys(sock, key, NULL) */ +void en_get_rsa_remote_publickey(esock_t sock, struct en_rsa_pub* remote); /* Same as en_publickeys(sock, NULL, key) */ +char* en_rsa_pub_f(char* buffer, int bs, const struct en_rsa_pub *key); /* Convert the en_rsa_pub key to a readable string in buffer `buffer'. */ +char* en_aes_f(char* buffer, int bs, const struct en_aes_key *key); /* Convert the en_aes_key to a readable string in buffer `buffer'. */ +void en_setflags(esock_t sock, unsigned int flags); /* Set special flags for `sock'. See EN_SOCKFLAG_* macros above. */ +unsigned int en_getflags(esock_t sock); /* Get flags for `sock' */ +void en_log(esock_t sock, ssize_t *r, ssize_t *w, int reset); /* Get the log data (EN_SOCKFLAG_LOG) from `sock'. If `r' or `w' is NULL, it is ignored. If `reset' is nonzero the internal values will then be reset. */ +float en_version(); /* Return build version (defined in file "VERSION"). */ +void en_set_timeout(esock_t sock, long value); /* Set the force-block timeout (in miliseconds) (0 for infinite) */ +long en_get_timeout(esock_t sock); /* Get the force-block timeout (default 0: infinite) */ +void en_seterrjmp(esock_t sock, jmp_buf *buffer); /* Set longjmp on error (or NULL). setjmp() value will be the error code. After a jump to this buffer, the pointer is reset to NULL. */ + +#endif /* _ENET_H */ diff --git a/include/internal/crc.h b/include/internal/crc.h new file mode 100644 index 0000000..157d1f7 --- /dev/null +++ b/include/internal/crc.h @@ -0,0 +1,11 @@ +#ifndef _CRC_H +#define _CRC_H +#include +#include + +#define _EN_CRC_TABLE_SIZE 256 +#define _EN_CRC_ITERATIONS 8 + +unsigned long _en_crc32(unsigned long seed, const unsigned char* buffer,unsigned int len); + +#endif /* _CRC_H */ diff --git a/include/internal/errors.h b/include/internal/errors.h new file mode 100644 index 0000000..83e751c --- /dev/null +++ b/include/internal/errors.h @@ -0,0 +1,11 @@ +#ifndef _ERRORS_H +#define _ERRORS_H +#include + +typedef _Atomic unsigned int _en_ecode_t; + +const char* _ene_get_header_message(_en_ecode_t code); +const char* _ene_get_detailed_message(_en_ecode_t code); +char* _ene_get_full_message(char *buf, int bs, _en_ecode_t code); + +#endif /* _ERRORS_H */ diff --git a/include/internal/smem.h b/include/internal/smem.h new file mode 100644 index 0000000..46af7b2 --- /dev/null +++ b/include/internal/smem.h @@ -0,0 +1,15 @@ +#ifndef _SMEM_H +#define _SMEM_H + +#define SM_ZERO_MEMORY + +#define sm_context _en_sm_context + +typedef struct __en_sm_context *sm_context; + +sm_context _en_sm_init(); +void _en_sm_free(sm_context s); +void* _en_smalloc(sm_context s, size_t size); +int _en_sm_clear(sm_context s); + +#endif /* _SMEM_H */ diff --git a/src/crc.c b/src/crc.c new file mode 100644 index 0000000..aca9dc2 --- /dev/null +++ b/src/crc.c @@ -0,0 +1,52 @@ +#include + +static const uint32_t __en_crc_poly = 0xedb88320u; + +static uint32_t __en_crc_table[_EN_CRC_TABLE_SIZE]; +static _Atomic volatile int __en_crc_initialised=0; + +static _Atomic volatile int __initialising=0; + +static uint32_t* __en_crc_create_table(uint32_t* table, uint32_t poly) +{ + register int i=0; + for(;i<_EN_CRC_TABLE_SIZE;i++) + { + register int j=0; + uint32_t e = (uint32_t)i; + for(;j<_EN_CRC_ITERATIONS;j++) + { + if( (e&1) == 1) + e = (e>>1) ^ poly; + else e = e>>1; + } + table[i] = e; + } + return table; +} + +static uint32_t __en_crc_calc(uint32_t* table, uint32_t seed, const unsigned char* buffer, int len) +{ + uint32_t crc= seed; + register int i=0; + for(;i>8) ^ table[(buffer[i] ^ crc) & 0xff]; + } + return crc; +} + +unsigned long _en_crc32(unsigned long seed, const unsigned char* buffer,unsigned int len) +{ + while(__initialising) (void)0; + + if(!__en_crc_initialised) + { + __initialising=1; + __en_crc_create_table(__en_crc_table,__en_crc_poly); + __en_crc_initialised=1; + __initialising=0; + + } + return ~__en_crc_calc(__en_crc_table, (uint32_t) seed, buffer, (int)len); +} diff --git a/src/enet.c b/src/enet.c new file mode 100644 index 0000000..ae1c555 --- /dev/null +++ b/src/enet.c @@ -0,0 +1,724 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#if defined(_EN_CUSTOM_CRC) +# include +# define crc32 _en_crc32 +#else +# include +#endif + +#ifndef __VERSION +#define __VERSION 0 /* No version defined by Make? */ +#endif + +#define ISFLAG(haystack, needle) ((needle & haystack) == needle) + +#define HTON(sock, val, s) (_en_flagset(sock, EN_SOCKFLAG_NO_HTON)?val:hton##s(val)) +#define NTOH(sock, val, s) (_en_flagset(sock, EN_SOCKFLAG_NO_HTON)?val:ntoh##s(val)) + +#define EN_ERRBUFF_SIZE 256 +#define EN_TMPBUFF_SIZE 512 + +///TODO: Mutexes & thread safety (maybe?) +///TODO: Make work on Windows/MinGW + +struct esock_t { + int con; + + RSA *local, *remote; + + struct en_aes_key aes_read_key, aes_write_key; + EVP_CIPHER_CTX *aes_read, *aes_write; + + _en_ecode_t errorcode; + + ssize_t log_read; + ssize_t log_written; + + long fb_timeout; + + jmp_buf* errjmp; + + unsigned int flags; + + sm_context smc_read; + sm_context smc_read_ct; + + char errbuff[EN_ERRBUFF_SIZE]; + char tmpbuff[EN_TMPBUFF_SIZE]; +}; + +#define _EN_FAIL(sock, ec) { sock->errorcode = ec; return EN_FAILURE; } + +static int _en_sockblock(int fd, int blocking) +{ + int flags = fcntl(fd, F_GETFL, 0); + if (flags == -1) return 0; + flags = blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK); + return (fcntl(fd, F_SETFL, flags) == 0) ? 1 : 0; +} + +static long _en_timems() +{ + struct timespec sp; + clock_gettime(CLOCK_REALTIME, &sp); + + return (sp.tv_sec*1000)+((long)(sp.tv_nsec/1.e6)); +} + +EVP_CIPHER_CTX* en_readAES(esock_t sock) +{ + return sock->aes_read; +} + +EVP_CIPHER_CTX* en_writeAES(esock_t sock) +{ + return sock->aes_write; +} + +static void _en_fail_jmp(esock_t sock) +{ + if(sock->errjmp!=NULL) { + jmp_buf *buf; + buf = sock->errjmp; + sock->errjmp=NULL; + longjmp(*buf, sock->errorcode); + } +} + +static int _en_fail(esock_t sock, int ec) +{ + sock->errorcode = ec; + _en_fail_jmp(sock); + return EN_FAILURE; +} + +static int _en_fail_nj(esock_t sock, int ec) +{ + sock->errorcode = ec; + return EN_FAILURE; +} + +void en_seterrjmp(esock_t sock, jmp_buf *buffer) +{ + sock->errjmp = buffer; +} + +static RSA* _en_create_keypair() +{ + return RSA_generate_key(EN_RSA_KEYSIZE, EN_RSA_EXP, NULL, NULL); +} + +static int _en_flagset(esock_t s, unsigned int f) +{ + return ISFLAG(s->flags, f); +} + +esock_t en_create_socket(int con, RSA *rsa) +{ + esock_t es = (esock_t)malloc(sizeof(struct esock_t)); + memset(es, 0, sizeof(struct esock_t)); + + es->con = con; + es->local = (rsa==NULL?_en_create_keypair():rsa); + es->remote = NULL; + es->smc_read = _en_sm_init(); + es->smc_read_ct = _en_sm_init(); + + es->aes_read = es->aes_write = NULL; + + return es; +} + +static struct en_rsa_pub _en_get_pub(RSA *rsa) +{ + struct en_rsa_pub pub; + const BIGNUM* n, *e; + + memset(&pub,0,sizeof(struct en_rsa_pub)); + + RSA_get0_key(rsa, &n, &e, NULL); + + assert( (BN_num_bytes(e)<=EN_RSAP_EXPSIZE) && (BN_num_bytes(n) == EN_RSAP_MODSIZE) ); + + BN_bn2bin(n, pub.mod); + + BN_bn2bin(e, pub.exp); + + return pub; +} + +RSA* en_localRSA(esock_t sock) +{ + return sock->local; +} + +RSA* en_remoteRSA(esock_t sock) +{ + return sock->remote; +} + +void en_publickeys(esock_t sock, struct en_rsa_pub *local, struct en_rsa_pub *remote) +{ + if(local!=NULL) + *local = _en_get_pub(sock->local); + if(remote!=NULL) + *remote = _en_get_pub(sock->remote); +} + +static char* _en_hexstr(char* buf, int bs, const unsigned char* bytes, int num) +{ + register int i=0; + char* nb = buf; + for(;(i*2)mod, EN_RSAP_MODSIZE); + _en_hexstr(exps, (EN_RSAP_EXPSIZE*2), key->exp, EN_RSAP_EXPSIZE); + snprintf(buffer,bs,"[mod: %s, exp: %s (crc32: %lx)]", mods, exps, crc32(EN_CRC32_SEED, (const unsigned char*)key, sizeof(struct en_rsa_pub))); + return buffer; +} + +static ssize_t __en_read(int con, unsigned char* buf, int len) +{ + ssize_t ret = read(con, buf,len); + if(ret<0) return 0; + return ret; +} + +static ssize_t _en_forceread(esock_t con, unsigned char* buf, int len, jmp_buf oto) +{ + ssize_t vr=0; + long tm_begin= _en_timems(); + //printf("_en_forceread: begining loop with time %ld (timeout %ld)\r\n", tm_begin, con->fb_timeout); + while( (vr+=__en_read(con->con, buf+vr, len-vr)) != len) { + if(con->fb_timeout>0) { + long tm_now = _en_timems(); + //printf("_en_forceread: new time is %ld (countdown: %ld)\r\n", tm_now, (tm_now-tm_begin)); + if( (tm_now-tm_begin)>=con->fb_timeout) { longjmp(oto, 1); } + } + } + return vr; +} + +static ssize_t _en_read(esock_t con, void* buf, int len, jmp_buf lje) +{ + if(_en_flagset(con, EN_SOCKFLAG_FORCEBLOCK)) return _en_forceread(con,(unsigned char*)buf,len, lje); + else + { + //printf("_en_read: using normal read\r\n"); + return read(con->con, buf, len); + } +} + +int en_exchange(esock_t sock) +{ + struct en_rsa_pub pub = _en_get_pub(sock->local); + struct en_rsa_pub rpub; + uint32_t local_crc,remote_crc; + jmp_buf to0; + + if( setjmp(to0)!=0) + { + return _en_fail(sock, ENE_READ_TIMEOUT); + } + + int bypassCS = _en_flagset(sock,EN_SOCKFLAG_NOCHECKSUM); + + local_crc= HTON(sock, crc32(EN_CRC32_SEED, (unsigned char*)&pub, sizeof(struct en_rsa_pub)), l); + + if( write(sock->con, &pub, sizeof(struct en_rsa_pub)) != sizeof(struct en_rsa_pub)) return _en_fail(sock, ENE_RSAE_WRITE_FAIL); + if( write(sock->con, &local_crc, sizeof(uint32_t)) != sizeof(uint32_t)) return _en_fail(sock, ENE_RSAE_WRITE_FAIL); + if( _en_read(sock, &rpub, sizeof(struct en_rsa_pub), to0) == sizeof(struct en_rsa_pub)) + { + if( (_en_read(sock, &remote_crc, sizeof(uint32_t), to0) == sizeof(uint32_t))) + { + remote_crc = NTOH(sock, remote_crc, l); + if( bypassCS || ( crc32(EN_CRC32_SEED, (unsigned char*)&rpub, sizeof(struct en_rsa_pub))==remote_crc) ) + { + BIGNUM* n, *e; + if(sock->remote!=NULL) + RSA_free(sock->remote); + + n = BN_bin2bn(rpub.mod, EN_RSAP_MODSIZE, NULL); + e = BN_bin2bn(rpub.exp, EN_RSAP_EXPSIZE, NULL); + + sock->remote = _en_create_keypair(); + RSA_set0_key(sock->remote, n, e, NULL); + + /*BN_free(n); + BN_free(e);*/ //Do I need to do this? + return EN_SUCCESS; + } + return _en_fail(sock, ENE_RSAE_INVALID_CHECKSUM); + } + else return _en_fail(sock, ENE_RSAE_INCORRECT_SIZE); + } + else return _en_fail(sock, ENE_RSAE_INCORRECT_SIZE); +} + +static EVP_CIPHER_CTX* _en_aes_create(unsigned char* key, unsigned char* iv, int en) +{ + EVP_CIPHER_CTX* ctx; + if(!(ctx = EVP_CIPHER_CTX_new())) return NULL; + if(en) { + if(!EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv)) { EVP_CIPHER_CTX_free(ctx); return NULL; } + } + else { + if(!EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv)) { EVP_CIPHER_CTX_free(ctx); return NULL; } + } + return ctx; +} + + + + + +static int _en_set_uenc_write(esock_t s) +{ + if(s->aes_write==NULL) return _en_fail(s, ENE_USWRITE_NOT_AQUIRED); + EVP_CIPHER_CTX_free(s->aes_write); + s->aes_write = NULL; + return EN_SUCCESS; +} + +static int _en_set_uenc_read(esock_t s) +{ + if(s->aes_read==NULL) return _en_fail(s, ENE_USREAD_NOT_AQUIRED); + EVP_CIPHER_CTX_free(s->aes_read); + s->aes_read = NULL; + return EN_SUCCESS; +} + +static int _en_set_enc_write(esock_t s) +{ + if(s->aes_write !=NULL) return _en_fail(s, ENE_SWRITE_ALREADY_AQUIRED); + if(!RAND_bytes((unsigned char*)&s->aes_write_key, sizeof(struct en_aes_key))) return _en_fail(s, ENE_SWRITE_KEYGEN_FAILURE); + else { + unsigned char* ct = (unsigned char*)malloc(RSA_size(s->remote)); + int32_t len; + if( (len=RSA_public_encrypt(sizeof(struct en_aes_key), (unsigned char*)&s->aes_write_key, ct, s->remote, RSA_PKCS1_PADDING)) > 0) + { + uint32_t crc = HTON(s, crc32(EN_CRC32_SEED, (unsigned char*)ct, len),l); + len = (int32_t)HTON(s, (uint32_t)len, l); + + write(s->con, &len, sizeof(int32_t)); + write(s->con, ct, (int32_t)NTOH(s, (uint32_t)len, l)); + write(s->con, &crc, sizeof(uint32_t)); + } + else { free(ct); return _en_fail(s, ENE_SWRITE_SSL_FAILURE); } + free(ct); + if( (s->aes_write = _en_aes_create(s->aes_write_key.key, s->aes_write_key.iv, 1)) == NULL) return _en_fail(s, ENE_SWRITE_AES_FAILURE); + return EN_SUCCESS; + } +} + +static int _en_set_enc_read(esock_t s) +{ + if(s->aes_read != NULL) return _en_fail(s, ENE_SREAD_ALREADY_AQUIRED); + else { + int32_t len; + uint32_t crc; + unsigned char* ct; + int bypassCS = _en_flagset(s, EN_SOCKFLAG_NOCHECKSUM); + jmp_buf to0,to1; + + if(setjmp(to0)!=0) + { + return _en_fail(s, ENE_READ_TIMEOUT); + } + + if( _en_read(s, &len, sizeof(int32_t), to0) != sizeof(int32_t)) return _en_fail(s, ENE_SREAD_INCORRECT_SIZE); + len = (int32_t)NTOH(s, (uint32_t)len,l); + + ct = (unsigned char*)malloc(len); + + if(setjmp(to1)!=0) + { + free(ct); + return _en_fail(s, ENE_READ_TIMEOUT); + } + + if( _en_read(s, ct, len, to1) != len) {free(ct); return _en_fail(s, ENE_SREAD_INCORRECT_SIZE);} + if( _en_read(s, &crc, sizeof(uint32_t), to1) != sizeof(uint32_t)) {free(ct); return _en_fail(s, ENE_SREAD_INCORRECT_SIZE);} + crc = NTOH(s, crc, l); + if( bypassCS || (crc32(EN_CRC32_SEED, ct, len) == crc)) + { + unsigned char* dec = (unsigned char*)malloc(RSA_size(s->local)); + + if(RSA_private_decrypt(len, ct, dec, s->local, RSA_PKCS1_PADDING)>0) + { + memcpy(&s->aes_read_key, dec, sizeof(struct en_aes_key)); + free(dec); + free(ct); + + return ((s->aes_read = _en_aes_create(s->aes_read_key.key, s->aes_read_key.iv, 0))==NULL?_en_fail(s, ENE_SREAD_AES_FAILURE):EN_SUCCESS); + } + else { + free(dec); free(ct); return _en_fail(s, ENE_SREAD_SSL_FAILURE); + } + } + else { + free(ct); return _en_fail(s, ENE_SREAD_INVALID_CHECKSUM); + } + + } +} + +int en_set(esock_t sock, int flag, int on) +{ + if( ISFLAG(flag, EN_READ) ) + { + if(on) + { + return _en_set_enc_read(sock); + } + else return _en_set_uenc_read(sock); + } + if( ISFLAG(flag, EN_WRITE) ) { + if(on) + { + return _en_set_enc_write(sock); + } + else return _en_set_uenc_write(sock); + } + return _en_fail(sock, ENE_SET_UNKNOWN_FLAG); +} + +static int _en_roundUp(int numToRound, int multiple) +{ + int remainder; + if (multiple == 0) + return numToRound; + + remainder = abs(numToRound) % multiple; + if (remainder == 0) + return numToRound; + if (numToRound < 0) + return -(abs(numToRound) - remainder); + return numToRound + multiple - remainder; +} + +int en_get(esock_t sock, int flag) +{ + int iew = sock->aes_write!=NULL; + int ier = sock->aes_read!=NULL; + + int ok; + if( ISFLAG(flag, EN_READ) && ISFLAG(flag, EN_WRITE) ) ok = ier && iew; + else { + if( ISFLAG(flag, EN_READ) ) ok = ier; + if( ISFLAG(flag, EN_WRITE) ) ok = iew; + } + return ok; +} + +ssize_t en_write(esock_t sock, void* _buf, size_t count) +{ + unsigned char* buf = (unsigned char*)_buf; + if(en_get(sock, EN_WRITE)) + { + int rctl = count%16==0?count+16:_en_roundUp(count, 16); + unsigned char* ct = (unsigned char*)malloc(rctl); + int len, ctl; + int rv= -1; + ssize_t ret=-1; + memset(ct,0,rctl); + if(EVP_EncryptUpdate(sock->aes_write, ct, &len, buf, count)) + { + ctl=len; + if(EVP_EncryptFinal_ex(sock->aes_write, ct+len, &len)) + { + ctl+=len; + if( (ret = write(sock->con, ct, rctl))!=rctl) + { + rv = _en_fail_nj(sock, ENE_WRITE_FAIL); + } + if(_en_flagset(sock, EN_SOCKFLAG_LOG)) sock->log_written+=count; + EVP_CIPHER_CTX_free(sock->aes_write); + if( (sock->aes_write = _en_aes_create(sock->aes_write_key.key, sock->aes_write_key.iv,1)) == NULL) rv = _en_fail_nj(sock, ENE_WRITE_AES_RELOAD_FAIL); + else if(rv!=EN_FAILURE) + rv = EN_SUCCESS; + + } else rv = _en_fail_nj(sock, ENE_WRITE_AES_FINAL_FAIL); + } else rv = _en_fail_nj(sock, ENE_WRITE_AES_UPDATE_FAIL); + free(ct); + if(rv== EN_SUCCESS) return ret; else { _en_fail_jmp(sock); return -1; } + } + else { + + ssize_t w = write(sock->con, buf,count); + if(_en_flagset(sock, EN_SOCKFLAG_LOG)) sock->log_written+=w; + return w; + } +} + + +ssize_t en_read(esock_t sock, void* _buf, size_t count) +{ + + if(en_get(sock, EN_READ)) + { + int rctl = count%16==0?count+16:_en_roundUp(count, 16); + unsigned char* ct = (unsigned char*)_en_smalloc(sock->smc_read_ct, rctl); + ssize_t ret=-1; + jmp_buf env_timeout; + + + unsigned char* buf = (unsigned char*)_en_smalloc(sock->smc_read, count+16+1); + + memset(buf,0,count+16); + buf[count+16]=0xaf; //this check is probably not needed anymore + + if (setjmp(env_timeout)!=0) + { + //timeout reached + _en_fail_nj(sock, ENE_READ_TIMEOUT); + } + else if( _en_read(sock, ct,rctl, env_timeout) == rctl ) + { + int len, ptl; + if(EVP_DecryptUpdate(sock->aes_read, buf, &len, ct, rctl)==1) + { + ptl = len; + if(EVP_DecryptFinal_ex(sock->aes_read, buf+len, &len)==1) + { + if(buf[count+16]!=0xaf) { + _en_fail(sock, ENE_FATAL_HEAP_CORRUPTION); + return -1; + } + else { + ptl+=len; + if(_en_flagset(sock, EN_SOCKFLAG_LOG)) sock->log_read+=count; + + memcpy(_buf, buf, count); + ret = ptl; + + } + } + else _en_fail_nj(sock, ENE_READ_AES_FINAL_FAIL); + } + else _en_fail_nj(sock, ENE_READ_AES_UPDATE_FAIL); + + EVP_CIPHER_CTX_free(sock->aes_read); + if( (sock->aes_read = _en_aes_create(sock->aes_read_key.key, sock->aes_read_key.iv,0)) == NULL) { + _en_fail_nj(sock, ENE_READ_AES_RELOAD_FAIL); + ret=-1; + } + + } + else { + _en_fail_nj(sock, ENE_READ_INCORRECT_SIZE); + } + _en_sm_clear(sock->smc_read); + _en_sm_clear(sock->smc_read_ct); + //free(ct); <-- V + //free(buf); <- sm_free is handled later + if(ret<=0) _en_fail_jmp(sock); + return ret; + } + else { + jmp_buf tob; + unsigned char* buf = (unsigned char*)_buf; + + if( setjmp(tob)!=0) + { + //timeout + _en_fail(sock, ENE_READ_TIMEOUT); + return -1; + } + else { + ssize_t r = _en_read(sock, buf, count, tob); + if(_en_flagset(sock, EN_SOCKFLAG_LOG)) sock->log_read+=r; + return r; + } + } +} + +void en_get_aes_read_key(esock_t sock, struct en_aes_key* key) +{ + memcpy(key, &sock->aes_read_key, sizeof(struct en_aes_key)); +} + +void en_get_aes_write_key(esock_t sock, struct en_aes_key* key) +{ + memcpy(key, &sock->aes_write_key, sizeof(struct en_aes_key)); +} + +char* en_aes_f(char* buffer, int bs, const struct en_aes_key *akey) +{ + char key[ (EN_AESP_KEYSIZE*2)+1]; + char iv[ (EN_AESP_IVSIZE*2)+1]; + memset(key, 0, (EN_AESP_KEYSIZE*2)+1); + memset(iv, 0, (EN_AESP_IVSIZE*2)+1); + _en_hexstr(key, (EN_AESP_KEYSIZE*2), akey->key, EN_AESP_KEYSIZE); + _en_hexstr(iv, (EN_AESP_IVSIZE*2), akey->iv, EN_AESP_IVSIZE); + snprintf(buffer,bs,"[key: %s, iv: %s (crc32: %lx)]", key, iv, crc32(EN_CRC32_SEED, (const unsigned char*)akey ,sizeof(struct en_aes_key))); + return buffer; +} + +void en_close(esock_t s, int flags) +{ + s->errjmp=NULL; + + _en_set_uenc_write(s); + _en_set_uenc_read(s); + + if(!ISFLAG(flags, EN_CLOSE_KEEPALIVE)) close(s->con); + if(!ISFLAG(flags, EN_CLOSE_KEEPRSA)) { + if(s->local!=NULL) RSA_free(s->local); + if(s->remote!=NULL) RSA_free(s->remote); + } + + _en_sm_free(s->smc_read); + _en_sm_free(s->smc_read_ct); + + memset(s, 0, sizeof(struct esock_t)); + free(s); +} + +const char* en_error(esock_t sock) +{ + char buf[512]; + //memset(sock->tmpbuff,0,EN_TMPBUFF_SIZE); + memset(buf,0,512); + memset(sock->errbuff,0,EN_ERRBUFF_SIZE); + snprintf(sock->errbuff, EN_ERRBUFF_SIZE-1, "[%u]%s", sock->errorcode, _ene_get_full_message(buf, 511, sock->errorcode)); + sock->errorcode=0; + return sock->errbuff; +} + +void en_aeskeys(esock_t sock, struct en_aes_key* write, struct en_aes_key* read) +{ + if(write!=NULL) en_get_aes_write_key(sock,write); + if(read!=NULL) en_get_aes_read_key( sock,read ); +} + +void en_get_rsa_local_publickey(esock_t sock, struct en_rsa_pub* local) +{ + en_publickeys(sock, local, NULL); +} + +void en_get_rsa_remote_publickey(esock_t sock, struct en_rsa_pub* remote) +{ + en_publickeys(sock, NULL, remote); +} + +void en_setflags(esock_t sock, unsigned int flags) +{ + sock->flags = flags; + + if(ISFLAG(flags, EN_SOCKFLAG_FORCEBLOCK)) _en_sockblock(sock->con, 0); + else _en_sockblock(sock->con, 1); +} + +unsigned int en_getflags(esock_t sock) +{ + return sock->flags; +} + +void en_log(esock_t sock, ssize_t *r, ssize_t *w, int reset) +{ + if(r!=NULL) *r = sock->log_read; + if(w!=NULL) *w = sock->log_written; + if(reset) { + sock->log_read = sock->log_written = 0; + } +} + +float en_version() +{ + return __VERSION; +} + +void en_set_timeout(esock_t sock, long value) +{ + sock->fb_timeout = value; +} + +long en_get_timeout(esock_t sock) {return sock->fb_timeout;} + +/* +void en_test(const unsigned char *plain, int pl, struct en_aes_key key) +{ + char __buf[1024]; + char __kbuf[1024]; + EVP_CIPHER_CTX* ctx; + + memset(__buf,0,1024); + memset(__kbuf,0,1024); + + printf("~~~~~ BEGIN TEST ~~~~~\r\n"); + printf("~[test]: Will encrypt plaintext \"%s\" with AES key %s\r\n", _en_hexstr(__buf, 1023, plain, pl), en_aes_f(__kbuf, 1023, &key)); + ctx = _en_aes_create(key.key,key.iv,1); + if(!ctx) + { + printf("~[test]: _en_aes_create failed\r\n"); + } + else { + int rctl = pl%16==0?pl+16:_en_roundUp(pl, 16); + int len; + int ctl; + unsigned char* ct = (unsigned char*)malloc(rctl); + memset(ct,0,rctl); + printf("~[test]: Allocated %d bytes for ciphertext (calculated from %d)\r\n", rctl, pl); + if(EVP_EncryptUpdate(ctx, ct, &len, plain, pl)) + { + ctl=len; + printf("~[test]: First call returned len %d\r\n",ctl); + if(EVP_EncryptFinal_ex(ctx, ct+len, &len)) + { + ctl+=len; + printf("~[test]: Second call returned len %d (+%d)\r\n", ctl, (ctl-len)); + if(ctl!=rctl) printf("~[test]: WARNING: Returned ciphertext length is not equal to expected\r\n"); + printf("~[test]: Ciphertext dump (%d bytes):", ctl); + BIO_dump_fp (stdout, (const char *)ct, ctl); + } + else { + printf("~[test]: EVP_EncryptFinal_ex failed\r\n"); + } + } + else { + printf("~[test]: EVP_EncryptUpdate failed\r\n"); + } + EVP_CIPHER_CTX_free(ctx); + } + printf("~~~~~ END TEST ~~~~~\r\n"); +}*/ diff --git a/src/errors.c b/src/errors.c new file mode 100644 index 0000000..64a9213 --- /dev/null +++ b/src/errors.c @@ -0,0 +1,93 @@ +#include +#include +#include +#include + +#include + +typedef struct { + _en_ecode_t code; + const char* desc; +} _en_error_t; + +_en_error_t _en_errors[] = { + {ENE_SREAD_ERROR, "(ENE_SREAD_ERROR)"}, + {ENE_SREAD_INCORRECT_SIZE, "Could not read correct number of bytes from stream"}, + {ENE_SREAD_INVALID_CHECKSUM, "Checksum mismatch"}, + {ENE_SREAD_SSL_FAILURE, "RSA decryption failed"}, + {ENE_SREAD_AES_FAILURE, "Could not aquire AES EVP cipher context"}, + {ENE_SREAD_ALREADY_AQUIRED, "Context already aquired (call en_set(sock, EN_READ, 0) first)"}, + + {ENE_RSAE_ERROR, "(ENE_RSAE_ERROR)"}, + {ENE_RSAE_INCORRECT_SIZE, "Could not read correct number of bytes from stream"}, + {ENE_RSAE_INVALID_CHECKSUM, "Checksum mismatch"}, + {ENE_RSAE_WRITE_FAIL, "Could not write correct number of bytes to stream"}, + + {ENE_SET_ERROR, "(ENE_SET_ERROR)"}, + {ENE_SET_UNKNOWN_FLAG, "Unknown flag"}, + + {ENE_SWRITE_ERROR, "(ENE_SWRITE_ERROR)"}, + {ENE_SWRITE_SSL_FAILURE, "RSA encryption failed"}, + {ENE_SWRITE_AES_FAILURE, "Could not aquire AES EVP cipher context"}, + {ENE_SWRITE_KEYGEN_FAILURE, "Could not generate random bytes for AES key"}, + {ENE_SWRITE_ALREADY_AQUIRED, "Context already aquired (call en_set(sock, EN_WRITE, 0) first)"}, + + {ENE_USREAD_ERROR, "(ENE_USREAD_ERROR)"}, + {ENE_USREAD_NOT_AQUIRED, "Context is not aquired"}, + + {ENE_USWRITE_ERROR, "(ENE_USWRITE_ERROR)"}, + {ENE_USWRITE_NOT_AQUIRED, "Conext is not aquired"}, + + {ENE_WRITE_ERROR, "(ENE_WRITE_ERROR)"}, + {ENE_WRITE_AES_RELOAD_FAIL, "Could not re-aquire AES EVP cipher context after encryption"}, + {ENE_WRITE_AES_UPDATE_FAIL, "Encryption failed on first transform"}, + {ENE_WRITE_AES_FINAL_FAIL, "Encryption failed on last transform (finalisation)"}, + {ENE_WRITE_FAIL, "Could not write full buffer (partial writes are not supported)"}, + + {ENE_READ_ERROR, "(ENE_READ_ERROR)"}, + {ENE_READ_AES_RELOAD_FAIL, "Could not re-aquire AES EVP cipher context after decryption"}, + {ENE_READ_AES_UPDATE_FAIL, "Decryption failed on first transform"}, + {ENE_READ_AES_FINAL_FAIL, "Decryption failed on last transform (finalisation)"}, + {ENE_READ_INCORRECT_SIZE, "Could not read full buffer (partial reads are not supported)"}, + {ENE_READ_TIMEOUT, "Read timeout was reached"}, + + {ENE_FATAL_ERROR, "(ENE_FATAL_ERROR)"}, + {ENE_FATAL_HEAP_CORRUPTION, "Heap corruption likely on decrypt call"}, + + {0,NULL}, +}; + +static const char* __ene_lookup(_en_ecode_t code) +{ + register int i=0; + for(;_en_errors[i].desc!=NULL; i++) + { + if(_en_errors[i].code == code) return _en_errors[i].desc; + } + return NULL; +} + +const char* _ene_get_header_message(_en_ecode_t code) +{ + unsigned int tr = (code>>8)<<8; + return __ene_lookup(tr); +} + +const char* _ene_get_detailed_message(_en_ecode_t code) +{ + return __ene_lookup(code); +} + +char* _ene_get_full_message(char *buf, int bs, _en_ecode_t code) +{ + //static char buf[512]; + const char* h; + const char* d; + memset(buf,0,bs); + + h = _ene_get_header_message(code); + d = _ene_get_detailed_message(code); + + snprintf(buf, bs-1, "%s: %s", (h==NULL?"(unbound)":h), (d==NULL?"(unbound)":d)); + return buf; +} diff --git a/src/smem.c b/src/smem.c new file mode 100644 index 0000000..91e65d1 --- /dev/null +++ b/src/smem.c @@ -0,0 +1,68 @@ +#include +#include +#include +#include +#include + +struct __en_sm_context { + void* ptr; + size_t size; +}; + +sm_context _en_sm_init() +{ + sm_context s = (sm_context)malloc(sizeof(struct __en_sm_context)); + memset(s, 0, sizeof(struct __en_sm_context)); + return s; +} + +void _en_sm_free(sm_context s) +{ + if(s->ptr!=NULL) + { +#ifdef SM_ZERO_MEMORY + memset(s->ptr,0,s->size); +#endif + free(s->ptr); + s->ptr=NULL; + } + s->size=0; + free(s); +} + +void* _en_smalloc(sm_context s, size_t size) +{ + if(s->ptr==NULL) + { + s->size=size; + s->ptr=malloc(size); +#ifdef SM_ZERO_MEMORY + memset(s->ptr,0,size); +#endif + return s->ptr; + } + else { + if(s->size==size) { +#ifdef SM_ZERO_MEMORY + memset(s->ptr,0,s->size); +#endif + return s->ptr; + } + else { + free(s->ptr); + s->size=0; + s->ptr = NULL; + return _en_smalloc(s, size); + } + } +} + +int _en_sm_clear(sm_context s) +{ + if(s->ptr!=NULL) + { + memset(s->ptr, 0, s->size); + return 1; + } + return 0; +} diff --git a/src/test/main.c b/src/test/main.c new file mode 100644 index 0000000..82a5f77 --- /dev/null +++ b/src/test/main.c @@ -0,0 +1,386 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include + +volatile _Atomic int running=1; + +#define PORT 8999 + +#define PF_CLIENT "[client]:" +#define PF_SERVER "[server]:" + +const int show_pd=0; + +void hex2str(char* buf, int bs, const unsigned char* bytes, int num) +{ + register int i=0; + char* nb = buf; + for(;(i*2) 0) + { + buffer[le]=0; + + if(fp) + { + fprintf(fp, "%s", buffer); + } + + SHA1(hash, SHA_DIGEST_LENGTH+1024, thash); + memcpy(hash, thash, SHA_DIGEST_LENGTH); + } + BIO_free(keybio); + memset(str,0,(SHA_DIGEST_LENGTH*2)+1); + hex2str(str, (SHA_DIGEST_LENGTH*2), hash, SHA_DIGEST_LENGTH); + printf("%s%s", begin, str); +} + + + +char* publicdatastr(char *buffer, int bs, esock_t sock, int remote) +{ + struct en_rsa_pub key; + if(!remote) + { + en_publickeys(sock, &key, NULL); + } + else { + en_publickeys(sock, NULL, &key); + } + memset(buffer, 0, bs); + return en_rsa_pub_f(buffer, bs, &key); +} + +char* aesdatastr(char *buffer, int bs, esock_t sock, int read) +{ + struct en_aes_key key; + if(!read) + { + en_get_aes_write_key(sock, &key); + } + else { + en_get_aes_read_key(sock, &key); + } + memset(buffer,0,bs); + return en_aes_f(buffer,bs, &key); +} + +void printSHA1(char * begin, const void* _data, int ds) +{ + const unsigned char* data = (const unsigned char*)_data; + unsigned char buf[SHA_DIGEST_LENGTH]; + char str[(SHA_DIGEST_LENGTH*2)+1]; + memset(str,0,(SHA_DIGEST_LENGTH*2)+1); + SHA1(data, ds, buf); + hex2str(str, (SHA_DIGEST_LENGTH*2), buf, SHA_DIGEST_LENGTH); + printf("%s%s", begin, str); +} + +void server_enc(int con) +{ + esock_t sock = en_create_socket(con, NULL); + struct en_rsa_pub us,them; + char _pd_buf[2048]; + char buffer[16]; + ssize_t l_r, l_w; + FILE* keyfile = fopen("srv_key_local.txt", "w"); + + en_addflag(sock, EN_SOCKFLAG_FORCEBLOCK); //enable force-blocking + en_addflag(sock, EN_SOCKFLAG_LOG); + + en_set_timeout(sock, 5000); //set timeout to 5 seconds + + en_publickeys(sock, &us, NULL); + printf(PF_SERVER " Socket created. Our RSA key is:\r\n"); + printRSA (PF_SERVER "\t[all](sha1)", keyfile, en_localRSA(sock)); + printf("\r\n"); + printSHA1(PF_SERVER "\t[pub](sha1)", &us, sizeof(struct en_rsa_pub)); + fclose(keyfile); + printf("\r\n"); + if(show_pd) printf(PF_SERVER "\t(public data)%s\r\n", publicdatastr(_pd_buf, 2047, sock, 0)); + if( EN_SUCCESS == en_exchange(sock)) { + FILE* rkf = fopen("srv_key_remote.txt", "w"); + + en_publickeys(sock, NULL, &them); + printf(PF_SERVER " exchange success, remote RSA is:\r\n"); + printRSA (PF_SERVER "\t[all](sha1)", rkf, en_remoteRSA(sock)); + printf("\r\n"); + printSHA1(PF_SERVER "\t[pub](sha1)", &them, sizeof(struct en_rsa_pub)); + fclose(rkf); + printf("\r\n"); + if(show_pd) printf(PF_SERVER "\t(public data)%s\r\n", publicdatastr(_pd_buf, 2047, sock, 1)); + } + else {printf(PF_SERVER " exchange failure: %s\r\n", en_error(sock));goto si_end;} + + sleep(1); + if(en_set(sock, EN_READ, 1) == EN_SUCCESS) + { + char _pd_aes[2048]; + printf(PF_SERVER " en_set (READ) success\r\n"); + memset(_pd_aes,0,2048); + printf(PF_SERVER "\tread AES key is:\t%s\r\n", aesdatastr(_pd_aes, 2047, sock ,1)); + + } + else {printf(PF_SERVER " en_set (READ) failure: %s\r\n", en_error(sock));goto si_end;} + + if(en_read(sock, buffer, 16)>0){ + buffer[15]=0; + printf(PF_SERVER " Client sent message: \"%s\"\r\n", buffer); + } + else { + printf(PF_SERVER " Read from socket failed: %s\r\n", en_error(sock)); + + ERR_print_errors_fp(stderr); + goto si_end; + } + en_set(sock, EN_READ, 0); + + en_log(sock, &l_r, &l_w, 1); + printf(PF_SERVER " We read %d bytes and wrote %d bytes\r\n", (int)l_r, (int)l_w); + sleep(1); +si_end: + en_close(sock, 0); +} + +void client_enc(int con) +{ + esock_t sock = en_create_socket(con, NULL); + struct en_rsa_pub us,them; + char _pd_buf[2048]; + char buffer[16]; + ssize_t l_r,l_w; + FILE* keyfile = fopen("cli_key_local.txt", "w"); + + en_addflag(sock, EN_SOCKFLAG_FORCEBLOCK); + en_addflag(sock, EN_SOCKFLAG_LOG); + + en_publickeys(sock, &us, NULL); + printf(PF_CLIENT " Socket created. Our RSA key is:\r\n"); + printRSA(PF_CLIENT "\t[all](sha1)",keyfile, en_localRSA(sock)); + printf("\r\n"); + printSHA1(PF_CLIENT "\t[pub](sha1)", &us, sizeof(struct en_rsa_pub)); + fclose(keyfile); + printf("\r\n"); + if(show_pd) printf(PF_CLIENT "\t(public data)%s\r\n", publicdatastr(_pd_buf, 2047, sock, 0)); + if( EN_SUCCESS == en_exchange(sock)) { + FILE* rkf = fopen("cli_key_remote.txt", "w"); + + en_publickeys(sock, NULL, &them); + printf(PF_CLIENT " exchange success, remote RSA is:\r\n"); + printRSA(PF_CLIENT "\t[all](sha1)", rkf, en_remoteRSA(sock)); + printf("\r\n"); + printSHA1(PF_CLIENT "\t[pub](sha1)", &them, sizeof(struct en_rsa_pub)); + fclose(rkf); + printf("\r\n"); + if(show_pd) printf(PF_CLIENT "\t(public data)%s\r\n", publicdatastr(_pd_buf, 2047, sock, 1)); + + } else {printf(PF_CLIENT " exchange failure: %s\r\n", en_error(sock));goto ci_end;} + + if(en_set(sock, EN_WRITE, 1) == EN_SUCCESS) + { + char _pd_aes[2048]; + printf(PF_CLIENT " en_set (WRITE) success\r\n"); + memset(_pd_aes,0,2048); + printf(PF_CLIENT "\twritten AES key is:\t%s\r\n", aesdatastr(_pd_aes, 2047, sock , 0)); + } + else {printf(PF_CLIENT " en_set (WRITE) failure: %s\r\n", en_error(sock)); goto ci_end;} + + memset(buffer,0,16); + snprintf(buffer, 15, "Hello, world!"); + + if(en_write(sock, buffer, 16)>0) + { + printf(PF_CLIENT " Successfully sent message to server\r\n"); + } + else { + printf(PF_CLIENT " Failed writing message to server: %s\r\n", en_error(sock)); + goto ci_end; + } + + en_set(sock, EN_WRITE, 0); + + en_log(sock, &l_r, &l_w, 1); + printf(PF_CLIENT " We read %d bytes and wrote %d bytes\r\n", (int)l_r, (int)l_w); + sleep(10); +ci_end: + en_close(sock, 0); +} + +void * cliw(void* _) +{ + int sock = socket(AF_INET , SOCK_STREAM , 0); + struct sockaddr_in server; + + server.sin_addr.s_addr = inet_addr("127.0.0.1"); + server.sin_family = AF_INET; + server.sin_port = htons(PORT); + sleep(1); + if (connect(sock, (struct sockaddr *)&server , sizeof(server)) == 0) { + printf(PF_CLIENT " Connection success\r\n"); + client_enc(sock); + //close(sock); + } else { + printf(PF_CLIENT " Connection failure\r\n"); + return NULL; + } + printf(PF_CLIENT " Connection closed\r\n"); + return NULL; +} + +void * srvw(void * _) +{ + struct sockaddr_in addr; + pthread_t cli; + struct sockaddr client_addr; + socklen_t client_addr_len; + int cs; + + int s = socket(AF_INET, SOCK_STREAM, 0); + + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_ANY); + addr.sin_port = htons(PORT); + + + bind(s, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)); + listen(s, 5); + + printf(PF_SERVER " Listening...\r\n"); + + pthread_create(&cli, NULL, &cliw, NULL); + + if( (cs = accept(s, &client_addr, &client_addr_len)) ) + { + printf(PF_SERVER " Connection success\r\n"); + server_enc(cs); + //close(cs); + } + printf(PF_SERVER " Connection closed\r\n"); + close(s); + running=0; + + return NULL; +} + +/*void cryptotest() +{ + char string[] = "Test string"; + struct en_aes_key key; + + RAND_bytes((unsigned char*)&key, sizeof(struct en_aes_key)); + + en_test((unsigned char*)string, strlen(string), key); +}*/ + +void extc_read(esock_t sock) +{ + int32_t rd; + int rrd; + char *buf; + if(en_read(sock, &rd, sizeof(int32_t))>0) { + printf("[read]: Allocating %d+1 bytes for read\r\n", rd); + buf = (char*)malloc(rd+1); + memset(buf,0,rd+1); + + if( (rrd=en_read(sock, buf, rd))<=0) + printf("[read]: Read failed: %s\r\n", en_error(sock)); + else + printf("[read]: Received string (%d bytes [expected %d]) \"%s\"\r\n", rrd, rd, buf); + free(buf); + printf("[read]: Done\r\n"); + } + else printf("[read]: Read size failed: %s\r\n", en_error(sock)); +} + +void extc_write(esock_t sock) +{ + char* buf= "TEST STRING FROM CLIENT"; + int32_t sz = strlen(buf); + + en_write(sock, &sz, sizeof(int32_t)); + en_write(sock, buf, sz); +} + +void extc(esock_t sock) +{ + if(en_exchange(sock)==EN_SUCCESS) + { + printf("Exchange success\r\n"); + + if(en_set(sock, EN_WRITE, 1)==EN_SUCCESS) { + printf("Set write success\r\n"); + extc_write(sock); + printf("Write data complete\r\n"); + en_set(sock, EN_WRITE, 0); + if(en_set(sock, EN_READ, 1)==EN_SUCCESS) + { + + printf("Set read success\r\n"); + extc_read(sock); + printf("Read data complete\r\n"); + en_set(sock, EN_READ, 0); + + } else printf("Set read error: %s\r\n", en_error(sock)); + } else printf("Set write error: %s\r\n", en_error(sock)); + + } + else { + printf("Exchange error: %s\r\n", en_error(sock)); + } +} + +int main(int argc, char** argv) +{ + pthread_t srv; + printf("Test of libenet v%.1f\r\n\r\n", en_version()); + if(argv[1]!=NULL&&strcmp(argv[1], "-con")==0) // Connect to remote host then do the following: exchange keys, set write context, write length of string (int32_t), write string, free write context, set read context, read length of string, read string, free read context, close connection. + { + int sock = socket(AF_INET , SOCK_STREAM , 0); + struct sockaddr_in server; + + server.sin_addr.s_addr = inet_addr(argv[2]); + server.sin_family = AF_INET; + server.sin_port = htons(9090); + if (connect(sock, (struct sockaddr *)&server , sizeof(server)) == 0) { + esock_t es = en_create_socket(sock, NULL); + extc(es); + printf("Done, last error on socket was \"%s\"\r\n", en_error(es)); + en_close(es, 0); + } + else printf("Connection failed\r\n"); + + return 0; + } + + /* Client server model test */ + + pthread_create(&srv, NULL, &srvw, NULL); + + while(running) sleep(1); + printf("[MAIN]: Exiting\r\n"); + return 0; +}