Initial Commit

master
flandre scarlet 7 years ago
commit c99a31e5db

3
.gitignore vendored

@ -0,0 +1,3 @@
maketar
other/
*~

@ -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'.

@ -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

@ -0,0 +1 @@
0.1

@ -0,0 +1,134 @@
#ifndef _ENET_H
#define _ENET_H
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <setjmp.h>
#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 */

@ -0,0 +1,11 @@
#ifndef _CRC_H
#define _CRC_H
#include <stdint.h>
#include <stdatomic.h>
#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 */

@ -0,0 +1,11 @@
#ifndef _ERRORS_H
#define _ERRORS_H
#include <stdatomic.h>
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 */

@ -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 */

@ -0,0 +1,52 @@
#include <internal/crc.h>
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<len;i++)
{
crc = (crc>>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);
}

@ -0,0 +1,724 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <sys/poll.h>
#include <stdatomic.h>
#include <assert.h>
#include <setjmp.h>
#include <stdint.h>
#include <fcntl.h>
#include <openssl/rsa.h>
#include <openssl/bn.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/aes.h>
#include <openssl/rand.h>
#include <enet.h>
#include <internal/errors.h>
#include <internal/smem.h>
#if defined(_EN_CUSTOM_CRC)
# include <internal/crc.h>
# define crc32 _en_crc32
#else
# include <zlib.h>
#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)<bs&&i<num;i++)
{
sprintf(nb, "%02x", bytes[i]);
nb+=2;
}
return buf;
}
char* en_rsa_pub_f(char* buffer, int bs, const struct en_rsa_pub *key)
{
char mods[ (EN_RSAP_MODSIZE*2)+1];
char exps[ (EN_RSAP_EXPSIZE*2)+1];
memset(mods, 0, (EN_RSAP_MODSIZE*2)+1);
memset(exps, 0, (EN_RSAP_EXPSIZE*2)+1);
_en_hexstr(mods, (EN_RSAP_MODSIZE*2), key->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");
}*/

@ -0,0 +1,93 @@
#include <enet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <internal/errors.h>
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;
}

@ -0,0 +1,68 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <internal/smem.h>
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;
}

@ -0,0 +1,386 @@
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <stdatomic.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <enet.h>
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)<bs&&i<num;i++)
{
sprintf(nb, "%02x", bytes[i]);
nb+=2;
}
}
void printRSA(const char* begin, FILE* fp, RSA* rsa)
{
char str[(SHA_DIGEST_LENGTH*2)+1];
unsigned char thash[SHA_DIGEST_LENGTH];
unsigned char hash[SHA_DIGEST_LENGTH+1024];
char* buffer = (char*) (hash+SHA_DIGEST_LENGTH);
int le;
BIO* keybio = BIO_new(BIO_s_mem());
RSA_print(keybio, rsa, 0);
memset(hash,0,SHA_DIGEST_LENGTH+1024);
while( (le=BIO_read(keybio, buffer, 1024)) > 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;
}
Loading…
Cancel
Save