commit
c99a31e5db
@ -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,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…
Reference in new issue