uninstall: | uninstall: | ||||
rm -f /usr/local/lib/libchat6.so | rm -f /usr/local/lib/libchat6.so | ||||
test: | |||||
$(MAKE) -C src test |
* neighbour: ipaddress,port | * neighbour: ipaddress,port | ||||
* metric: a 32 bits unsigned integer representing the sum of all latencies between the client and the announcing client. | * metric: a 32 bits unsigned integer representing the sum of all latencies between the client and the announcing client. | ||||
### begin and end of session | |||||
``` | |||||
HELLO {version} | |||||
BYE | |||||
``` | |||||
### path anouncement and withdrawal | ### path anouncement and withdrawal | ||||
``` | ``` | ||||
<TIMESTAMP> <PROOF> <MSGHASH> <KEY> KEEPALIVE RESPONSE | <TIMESTAMP> <PROOF> <MSGHASH> <KEY> KEEPALIVE RESPONSE | ||||
``` | ``` | ||||
### MESSAGE | |||||
### FRIENDS & MESSAGES | |||||
``` | ``` | ||||
<TIMESTAMP> <PROOF> <MSGHASH> <KEY> MESSAGE SEND {target_hash, chatid, msgid, key, message} | |||||
<TIMESTAMP> <PROOF> <MSGHASH> <KEY> FRIEND REQUEST {target_hash, key} | |||||
<TIMESTAMP> <PROOF> <MSGHASH> <KEY> FRIEND CONFIRM {target_hash, key} | |||||
<TIMESTAMP> <PROOF> <MSGHASH> <KEY> MESSAGE SEND {target_hash, chatid, msgid, message} | |||||
<TIMESTAMP> <PROOF> <MSGHASH> <KEY> MESSAGE RECV {target_hash, chatid, msgid} | <TIMESTAMP> <PROOF> <MSGHASH> <KEY> MESSAGE RECV {target_hash, chatid, msgid} | ||||
<TIMESTAMP> <PROOF> <MSGHASH> <KEY> MESSAGE READ {target_hash, chatid, msgid} | <TIMESTAMP> <PROOF> <MSGHASH> <KEY> MESSAGE READ {target_hash, chatid, msgid} | ||||
``` | ``` | ||||
``` | ``` | ||||
<TIMESTAMP> <PROOF> <MSGHASH> <KEY> NEIGHBORS REQUEST # request the neighbours of your neighbour | <TIMESTAMP> <PROOF> <MSGHASH> <KEY> NEIGHBORS REQUEST # request the neighbours of your neighbour | ||||
<TIMESTAMP> <PROOF> <MSGHASH> <KEY> NEIGHBORS RESPONSE {neighbour,..} # neighbours list, multiple time the same key | <TIMESTAMP> <PROOF> <MSGHASH> <KEY> NEIGHBORS RESPONSE {neighbour,..} # neighbours list, multiple time the same key | ||||
``` | |||||
``` |
#CCFLAGS := -fPIC -Wall -Werror -std=c11 -pedantic -O2 | #CCFLAGS := -fPIC -Wall -Werror -std=c11 -pedantic -O2 | ||||
CCFLAGS := -fPIC -Wall -Werror -std=c11 -pedantic -g | CCFLAGS := -fPIC -Wall -Werror -std=c11 -pedantic -g | ||||
LDFLAGS := | LDFLAGS := | ||||
LIBS := -lchat6 -lssl -lpthread -lcrypto | |||||
LIBS := -lchat6 -lssl -lpthread -lcrypto -lsodium | |||||
TARGETS:= libchat6.so libchat6.a | TARGETS:= libchat6.so libchat6.a | ||||
MAINS := $(.o, $(TARGETS) ) | MAINS := $(.o, $(TARGETS) ) | ||||
OBJ := \ | OBJ := \ | ||||
lc6_ssl.o \ | |||||
lc6_node.o \ | |||||
lc6_config.o \ | |||||
lc6_helpers.o \ | |||||
lc6_user.o \ | |||||
lc6_crypto.o \ | |||||
lc6_base64.o \ | |||||
libchat6.o \ | libchat6.o \ | ||||
$(MAINS) | $(MAINS) | ||||
DEPS := | DEPS := | ||||
ranlib $@ | ranlib $@ | ||||
test: test.o | test: test.o | ||||
$(CC) $(LDFLAGS) $^ -o $@ $(LIBS) | |||||
$(CC) $(CCFLAGS) $(LDFLAGS) $^ -o $@ $(LIBS) | |||||
/* | |||||
* Base64 encoding/decoding (RFC1341) | |||||
* Copyright (c) 2005-2011, Jouni Malinen <j@w1.fi> | |||||
* | |||||
* This software may be distributed under the terms of the BSD license. | |||||
* See README for more details. | |||||
*/ | |||||
#include <stdio.h> | |||||
#include <stdlib.h> | |||||
#include <string.h> | |||||
#include "lc6_base64.h" | |||||
static const unsigned char base64_table[65] = | |||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | |||||
/** | |||||
* base64_encode - Base64 encode | |||||
* @src: Data to be encoded | |||||
* @len: Length of the data to be encoded | |||||
* @out_len: Pointer to output length variable, or %NULL if not used | |||||
* Returns: Allocated buffer of out_len bytes of encoded data, | |||||
* or %NULL on failure | |||||
* | |||||
* Caller is responsible for freeing the returned buffer. Returned buffer is | |||||
* nul terminated to make it easier to use as a C string. The nul terminator is | |||||
* not included in out_len. | |||||
*/ | |||||
unsigned char* base64_encode(const unsigned char *src, size_t len, | |||||
size_t *out_len) | |||||
{ | |||||
unsigned char *out, *pos; | |||||
const unsigned char *end, *in; | |||||
size_t olen; | |||||
int line_len; | |||||
olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */ | |||||
olen += olen / 72; /* line feeds */ | |||||
olen++; /* nul termination */ | |||||
if (olen < len) | |||||
return NULL; /* integer overflow */ | |||||
out = malloc(olen); | |||||
if (out == NULL) | |||||
return NULL; | |||||
end = src + len; | |||||
in = src; | |||||
pos = out; | |||||
line_len = 0; | |||||
while (end - in >= 3) { | |||||
*pos++ = base64_table[in[0] >> 2]; | |||||
*pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)]; | |||||
*pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)]; | |||||
*pos++ = base64_table[in[2] & 0x3f]; | |||||
in += 3; | |||||
line_len += 4; | |||||
if (line_len >= 72) { | |||||
*pos++ = '\n'; | |||||
line_len = 0; | |||||
} | |||||
} | |||||
if (end - in) { | |||||
*pos++ = base64_table[in[0] >> 2]; | |||||
if (end - in == 1) { | |||||
*pos++ = base64_table[(in[0] & 0x03) << 4]; | |||||
*pos++ = '='; | |||||
} else { | |||||
*pos++ = base64_table[((in[0] & 0x03) << 4) | | |||||
(in[1] >> 4)]; | |||||
*pos++ = base64_table[(in[1] & 0x0f) << 2]; | |||||
} | |||||
*pos++ = '='; | |||||
line_len += 4; | |||||
} | |||||
if (line_len) | |||||
*pos++ = '\n'; | |||||
*pos = '\0'; | |||||
if (out_len) | |||||
*out_len = pos - out; | |||||
return out; | |||||
} | |||||
/** | |||||
* base64_decode - Base64 decode | |||||
* @src: Data to be decoded | |||||
* @len: Length of the data to be decoded | |||||
* @out_len: Pointer to output length variable | |||||
* Returns: Allocated buffer of out_len bytes of decoded data, | |||||
* or %NULL on failure | |||||
* | |||||
* Caller is responsible for freeing the returned buffer. | |||||
*/ | |||||
unsigned char * base64_decode(const unsigned char *src, size_t len, | |||||
size_t *out_len) | |||||
{ | |||||
unsigned char dtable[256], *out, *pos, block[4], tmp; | |||||
size_t i, count, olen; | |||||
int pad = 0; | |||||
memset(dtable, 0x80, 256); | |||||
for (i = 0; i < sizeof(base64_table) - 1; i++) | |||||
dtable[base64_table[i]] = (unsigned char) i; | |||||
dtable['='] = 0; | |||||
count = 0; | |||||
for (i = 0; i < len; i++) { | |||||
if (dtable[src[i]] != 0x80) | |||||
count++; | |||||
} | |||||
if (count == 0 || count % 4) | |||||
return NULL; | |||||
olen = count / 4 * 3; | |||||
pos = out = malloc(olen); | |||||
if (out == NULL) | |||||
return NULL; | |||||
count = 0; | |||||
for (i = 0; i < len; i++) { | |||||
tmp = dtable[src[i]]; | |||||
if (tmp == 0x80) | |||||
continue; | |||||
if (src[i] == '=') | |||||
pad++; | |||||
block[count] = tmp; | |||||
count++; | |||||
if (count == 4) { | |||||
*pos++ = (block[0] << 2) | (block[1] >> 4); | |||||
*pos++ = (block[1] << 4) | (block[2] >> 2); | |||||
*pos++ = (block[2] << 6) | block[3]; | |||||
count = 0; | |||||
if (pad) { | |||||
if (pad == 1) | |||||
pos--; | |||||
else if (pad == 2) | |||||
pos -= 2; | |||||
else { | |||||
/* Invalid padding */ | |||||
free(out); | |||||
return NULL; | |||||
} | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
*out_len = pos - out; | |||||
return out; | |||||
} |
#ifndef LC6_BASE64_H | |||||
#define LC6_BASE64_H | |||||
unsigned char* base64_encode(const unsigned char*, size_t, size_t*); | |||||
unsigned char* base64_decode(const unsigned char*, size_t, size_t*); | |||||
#endif | |||||
#include <stdio.h> | |||||
#include <stdlib.h> | |||||
#include <string.h> | |||||
#include <assert.h> | |||||
#include "lc6_config.h" | |||||
#include "lc6_crypto.h" | |||||
LC6_CTX* lc6config_load(unsigned char *password, char *path) { | |||||
LC6_CTX *conf; | |||||
conf = malloc(sizeof(LC6_CTX)); | |||||
assert(conf); | |||||
memset(conf, '\0', sizeof(LC6_CTX)); | |||||
lc6config_load_file(conf, path, LC6_CONFIG_BOOTSTRAP, password); | |||||
lc6config_load_file(conf, path, LC6_CONFIG_USER, password); | |||||
lc6config_load_file(conf, path, LC6_CONFIG_FRIENDS, password); | |||||
// complete defaults | |||||
// conf->path | |||||
strncpy(conf->path, path, sizeof(conf->path)); | |||||
conf->path[sizeof(conf->path)-1]='\0'; | |||||
// conf->node | |||||
// generate new keys at every startup. | |||||
// those are only used for direct signaling to | |||||
// the neighbours. | |||||
conf->node = malloc(sizeof(LC6_USER)); | |||||
assert(conf->node); | |||||
lc6crypto_genuserkey(conf->node); | |||||
// conf->user may stay NULL | |||||
// conf->friends maybe you're all alone, that's ok tho. | |||||
// conf->bootstrap | |||||
// this is a major issue if we can't bootstrap | |||||
if ( !conf->bootstrap ) | |||||
return NULL; | |||||
return conf; | |||||
} | |||||
void lc6config_load_file( | |||||
LC6_CTX *conf, | |||||
char *path, | |||||
char *filename, | |||||
unsigned char *password) | |||||
{ | |||||
unsigned char *data = NULL; | |||||
int data_len = 0; | |||||
char file[MAXPATHLEN]; | |||||
snprintf(file, sizeof(file), "%s/%s", path, filename); | |||||
if ( lc6crypto_readfile(file, password, &data, &data_len) != 0 ) | |||||
return; | |||||
if ( strcmp(filename, LC6_CONFIG_BOOTSTRAP) == 0 ) { | |||||
LC6_BOOTSTRAP *prev = NULL; | |||||
int offset = 0; | |||||
conf->bootstrap = (LC6_BOOTSTRAP*)data; | |||||
while(offset<data_len/sizeof(LC6_BOOTSTRAP)) { | |||||
LC6_BOOTSTRAP *node = conf->bootstrap + offset; | |||||
node->prev = prev; | |||||
node->next = NULL; | |||||
node->prev->next = node; | |||||
prev = node; | |||||
offset++; | |||||
} | |||||
} | |||||
else if ( strcmp(filename, LC6_CONFIG_USER) == 0 ) { | |||||
conf->user = (LC6_USER*)data; | |||||
} | |||||
else if ( strcmp(filename, LC6_CONFIG_FRIENDS) == 0 ) { | |||||
LC6_USER *prev = NULL; | |||||
int offset = 0; | |||||
conf->friends = (LC6_USER*)data; | |||||
while(offset<data_len/sizeof(LC6_USER)) { | |||||
LC6_USER *node = conf->friends + offset; | |||||
node->prev = prev; | |||||
node->next = NULL; | |||||
node->prev->next = node; | |||||
prev = node; | |||||
offset++; | |||||
} | |||||
} | |||||
} |
#ifndef LC6_CONFIG_H | |||||
#define LC6_CONFIG_H | |||||
#include <sys/param.h> | |||||
#include <arpa/inet.h> | |||||
#include "lc6_user.h" | |||||
#define LC6_CONFIG_BOOTSTRAP "bootstrap.bin" | |||||
#define LC6_CONFIG_USER "user.bin" | |||||
#define LC6_CONFIG_FRIENDS "friends.bin" | |||||
typedef struct LC6_BOOTSTRAP { | |||||
struct LC6_BOOTSTRAP *prev; | |||||
struct LC6_BOOTSTRAP *next; | |||||
time_t last_contact; | |||||
int af; | |||||
union addr { | |||||
struct in_addr inet; | |||||
struct in6_addr inet6; | |||||
} addr; | |||||
} LC6_BOOTSTRAP; | |||||
typedef struct LC6_CTX { | |||||
char path[MAXPATHLEN]; | |||||
LC6_USER *user; | |||||
LC6_USER *node; | |||||
LC6_USER *friends; | |||||
LC6_BOOTSTRAP *bootstrap; | |||||
} LC6_CTX; | |||||
LC6_CTX* lc6config_load(unsigned char *key, char *path); | |||||
void lc6config_load_file( | |||||
LC6_CTX *conf, | |||||
char *path, | |||||
char *filename, | |||||
unsigned char *password); | |||||
#endif |
#include <string.h> | |||||
#include <sodium.h> | |||||
#include <assert.h> | |||||
#include "lc6_crypto.h" | |||||
int lc6crypto_seeded = 0; | |||||
LC6_USER* lc6crypto_genuserkey(LC6_USER *user) { | |||||
assert(user); | |||||
user->pub_key = malloc(crypto_box_PUBLICKEYBYTES); | |||||
user->priv_key = malloc(crypto_box_SECRETKEYBYTES); | |||||
assert(user->pub_key); | |||||
assert(user->priv_key); | |||||
crypto_box_keypair(user->pub_key, user->priv_key); | |||||
return user; | |||||
} | |||||
int lc6crypto_public_encrypt( | |||||
const unsigned char *data, | |||||
const int data_len, | |||||
const unsigned char *priv, | |||||
const unsigned char *pub, | |||||
unsigned char **enc_data, | |||||
unsigned char **nonce) | |||||
{ | |||||
*nonce = malloc(crypto_box_NONCEBYTES); | |||||
assert(*nonce); | |||||
*enc_data = malloc(crypto_box_MACBYTES + data_len); | |||||
assert(*enc_data); | |||||
randombytes_buf(*nonce, crypto_box_NONCEBYTES); | |||||
if ( crypto_box_easy(*enc_data, data, data_len, *nonce, pub, priv) == -1 ) | |||||
return 0; | |||||
return crypto_box_MACBYTES + data_len; | |||||
} | |||||
int lc6crypto_private_decrypt( | |||||
const unsigned char *enc_data, | |||||
const int enc_len, | |||||
const unsigned char *priv, | |||||
const unsigned char *pub, | |||||
unsigned char **data, | |||||
const unsigned char *nonce) | |||||
{ | |||||
*data = malloc(enc_len - crypto_box_MACBYTES); | |||||
assert(data); | |||||
if ( crypto_box_open_easy(*data, enc_data, enc_len, nonce, pub, priv) != 0 ) | |||||
return 0; | |||||
return enc_len - crypto_box_MACBYTES; | |||||
} | |||||
int lc6crypto_private_encrypt( | |||||
const unsigned char *data, | |||||
const int data_len, | |||||
const unsigned char *priv, | |||||
const unsigned char *pub, | |||||
unsigned char **enc_data, | |||||
unsigned char **nonce) | |||||
{ | |||||
return lc6crypto_public_encrypt( | |||||
data, data_len, | |||||
pub, priv, | |||||
enc_data, nonce); | |||||
} | |||||
int lc6crypto_public_decrypt( | |||||
const unsigned char *enc_data, | |||||
const int enc_len, | |||||
const unsigned char *priv, | |||||
const unsigned char *pub, | |||||
unsigned char **data, | |||||
const unsigned char *nonce) | |||||
{ | |||||
return lc6crypto_private_decrypt( | |||||
enc_data, enc_len, | |||||
pub, priv, | |||||
data, nonce); | |||||
} | |||||
int lc6crypto_readfile( | |||||
const char *file, | |||||
const unsigned char *password, | |||||
unsigned char **data, | |||||
int *data_len) | |||||
{ | |||||
FILE *fh; | |||||
unsigned char hash[crypto_generichash_BYTES]; | |||||
unsigned char *encrypted; | |||||
size_t total = 0; | |||||
crypto_generichash(hash, sizeof hash, password, strlen((char*)password), NULL, 0); | |||||
if ( ( fh = fopen(file, "r") ) == NULL ) | |||||
return -1; | |||||
while(1) { | |||||
unsigned char buf[4096]; | |||||
size_t len; | |||||
len = fread(buf, sizeof(buf), 1, fh); | |||||
if ( len == 0 && !feof(fh) ) { | |||||
fclose(fh); | |||||
if ( encrypted ) | |||||
free(encrypted); | |||||
return -1; | |||||
} | |||||
if ( !encrypted ) | |||||
encrypted = malloc(len); | |||||
else | |||||
encrypted = realloc(encrypted, total + len); | |||||
assert(encrypted); | |||||
memcpy(encrypted + total, buf, len); | |||||
total+=len; | |||||
} | |||||
fclose(fh); | |||||
*data_len = total - crypto_secretbox_NONCEBYTES; | |||||
*data = malloc(*data_len); | |||||
assert(*data); | |||||
memset(*data, '\0', total - crypto_secretbox_NONCEBYTES); | |||||
if (crypto_secretbox_open_easy(*data, encrypted + crypto_secretbox_NONCEBYTES, *data_len, encrypted, hash) != 0) { | |||||
free(encrypted); | |||||
free(*data); | |||||
return -1; | |||||
} | |||||
free(encrypted); | |||||
return 0; | |||||
} | |||||
int lc6crypto_writefile( | |||||
const char *file, | |||||
const unsigned char *password, | |||||
const unsigned char *data, | |||||
const int data_len) | |||||
{ | |||||
FILE *fh; | |||||
unsigned char hash[crypto_generichash_BYTES]; | |||||
unsigned char nonce[crypto_secretbox_NONCEBYTES]; | |||||
unsigned char *encrypted; | |||||
int offset = 0; | |||||
crypto_generichash(hash, sizeof hash, password, strlen((char*)password), NULL, 0); | |||||
encrypted = malloc(data_len + crypto_secretbox_NONCEBYTES); | |||||
memcpy(encrypted, nonce, crypto_secretbox_NONCEBYTES); | |||||
crypto_secretbox_easy(encrypted + crypto_secretbox_NONCEBYTES, data, data_len, nonce, hash); | |||||
if ( ( fh = fopen(file, "w") ) == NULL ) | |||||
return -1; | |||||
if ( fwrite(encrypted + crypto_secretbox_NONCEBYTES + offset, data_len + crypto_secretbox_NONCEBYTES, 1, fh) != 1 ) { | |||||
free(encrypted); | |||||
return -1; | |||||
} | |||||
fclose(fh); | |||||
free(encrypted); | |||||
return 0; | |||||
} | |||||
unsigned char* lc6crypto_hash( | |||||
unsigned char *data, | |||||
int data_len) | |||||
{ | |||||
unsigned char *hash = malloc(crypto_generichash_BYTES); | |||||
assert(hash); | |||||
crypto_generichash(hash, sizeof hash, data, data_len, NULL, 0); | |||||
return hash; | |||||
} | |||||
void lc6crypto_random(unsigned char *data, int data_len) { | |||||
randombytes_buf(data, data_len); | |||||
} |
#ifndef LC6_SSL_H | |||||
#define LC6_SSL_H | |||||
#include "lc6_user.h" | |||||
int lc6crypto_public_encrypt( | |||||
const unsigned char *data, | |||||
const int data_len, | |||||
const unsigned char *priv, | |||||
const unsigned char *pub, | |||||
unsigned char **enc_data, | |||||
unsigned char **nonce); | |||||
int lc6crypto_private_decrypt( | |||||
const unsigned char *enc_data, | |||||
const int enc_len, | |||||
const unsigned char *priv, | |||||
const unsigned char *pub, | |||||
unsigned char **data, | |||||
const unsigned char *nonce); | |||||
int lc6crypto_private_encrypt( | |||||
const unsigned char *data, | |||||
const int data_len, | |||||
const unsigned char *priv, | |||||
const unsigned char *pub, | |||||
unsigned char **enc_data, | |||||
unsigned char **nonce); | |||||
int lc6crypto_public_decrypt( | |||||
const unsigned char *enc_data, | |||||
const int enc_len, | |||||
const unsigned char *priv, | |||||
const unsigned char *pub, | |||||
unsigned char **data, | |||||
const unsigned char *nonce); | |||||
int lc6crypto_readfile( | |||||
const char *file, | |||||
const unsigned char *password, | |||||
unsigned char **data, | |||||
int *data_len); | |||||
int lc6crypto_writefile( | |||||
const char *file, | |||||
const unsigned char *password, | |||||
const unsigned char *data, | |||||
const int data_len); | |||||
LC6_USER* lc6crypto_genuserkey(LC6_USER*); | |||||
unsigned char* lc6crypto_hash(unsigned char*, int); | |||||
void lc6crypto_random(unsigned char*, int); | |||||
#endif |
#include <openssl/rsa.h> | |||||
#include <openssl/pem.h> | |||||
#include <openssl/sha.h> | |||||
#include <openssl/rand.h> | |||||
#include <string.h> | |||||
#include <assert.h> | |||||
#include "lc6_crypto.h" | |||||
int lc6crypto_seeded = 0; | |||||
libchat_user* lc6crypto_genuserkey(libchat_user *user) { | |||||
BIGNUM *bn; | |||||
RSA *rsa; | |||||
BIO *pub; | |||||
BIO *priv; | |||||
size_t publen; | |||||
size_t privlen; | |||||
assert(user); | |||||
bn = BN_new(); | |||||
BN_set_word(bn, RSA_F4); | |||||
rsa = RSA_new(); | |||||
RSA_generate_key_ex(rsa, 2048, bn, NULL); | |||||
priv = BIO_new(BIO_s_mem()); | |||||
pub = BIO_new(BIO_s_mem()); | |||||
PEM_write_bio_RSAPrivateKey(priv, rsa, NULL, NULL, 0, NULL, NULL); | |||||
PEM_write_bio_RSAPublicKey(pub, rsa); | |||||
RSA_free(rsa); | |||||
privlen = BIO_pending(priv); | |||||
publen = BIO_pending(pub); | |||||
user->priv_key = malloc(privlen); | |||||
user->pub_key = malloc(publen); | |||||
BIO_read(priv, user->priv_key, privlen); | |||||
BIO_read(pub, user->pub_key, publen); | |||||
user->priv_key[privlen-1] = '\0'; | |||||
user->pub_key[publen-1] = '\0'; | |||||
BIO_free_all(priv); | |||||
BIO_free_all(pub); | |||||
BN_free(bn); | |||||
return user; | |||||
} | |||||
RSA * __lc6crypto_createRSA(unsigned char *key, int public) | |||||
{ | |||||
RSA *rsa= NULL; | |||||
BIO *keybio = NULL; | |||||
keybio = BIO_new_mem_buf(key, -1); | |||||
assert(keybio); | |||||
if(public) { | |||||
PEM_read_bio_RSA_PUBKEY(keybio, &rsa, NULL, NULL); | |||||
} | |||||
else { | |||||
PEM_read_bio_RSAPrivateKey(keybio, &rsa, NULL, NULL); | |||||
} | |||||
assert(rsa); | |||||
return rsa; | |||||
} | |||||
int lc6crypto_public_encrypt( | |||||
unsigned char *data, | |||||
int data_len, | |||||
unsigned char *key, | |||||
unsigned char *enc_data) | |||||
{ | |||||
RSA *rsa = __lc6crypto_createRSA(key,1); | |||||
int result = RSA_public_encrypt(data_len, data, enc_data, rsa, RSA_PKCS1_OAEP_PADDING); | |||||
return result; | |||||
} | |||||
int lc6crypto_private_decrypt( | |||||
unsigned char *enc_data, | |||||
int enc_len, | |||||
unsigned char *key, | |||||
unsigned char *data) | |||||
{ | |||||
RSA *rsa = __lc6crypto_createRSA(key,0); | |||||
int result = RSA_private_decrypt(enc_len, enc_data, data, rsa, RSA_PKCS1_OAEP_PADDING); | |||||
return result; | |||||
} | |||||
int lc6crypto_private_encrypt( | |||||
unsigned char *data, | |||||
int data_len, | |||||
unsigned char *key, | |||||
unsigned char *enc_data) | |||||
{ | |||||
RSA *rsa = __lc6crypto_createRSA(key,0); | |||||
int result = RSA_private_encrypt(data_len, data, enc_data, rsa, RSA_PKCS1_OAEP_PADDING); | |||||
return result; | |||||
} | |||||
int lc6crypto_public_decrypt( | |||||
unsigned char *enc_data, | |||||
int enc_len, | |||||
unsigned char *key, | |||||
unsigned char *data) | |||||
{ | |||||
RSA *rsa = __lc6crypto_createRSA(key,1); | |||||
int result = RSA_public_decrypt(enc_len, enc_data, data, rsa, RSA_PKCS1_OAEP_PADDING); | |||||
return result; | |||||
} | |||||
void lc6crypto_sha256( | |||||
unsigned char *data, | |||||
int data_len, | |||||
unsigned char *hash) | |||||
{ | |||||
SHA256_CTX sha256; | |||||
SHA256_Init(&sha256); | |||||
SHA256_Update(&sha256, data, data_len); | |||||
SHA256_Final(hash, &sha256); | |||||
} | |||||
int lc6crypto_encrypt( | |||||
unsigned char *data, | |||||
int data_len, | |||||
unsigned char *encrypted, | |||||
unsigned char *key, | |||||
unsigned char *iv) | |||||
{ | |||||
EVP_CIPHER_CTX *ctx; | |||||
int encrypted_len = 0; | |||||
int len = 0; | |||||
if(!(ctx = EVP_CIPHER_CTX_new())) | |||||
return -1; | |||||
if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv)) { | |||||
EVP_CIPHER_CTX_free(ctx); | |||||
return -1; | |||||
} | |||||
if(1 != EVP_EncryptUpdate(ctx, encrypted, &len, data, data_len)) { | |||||
EVP_CIPHER_CTX_free(ctx); | |||||
return -1; | |||||
} | |||||
encrypted_len += len; | |||||
if(1 != EVP_EncryptFinal_ex(ctx, encrypted + len, &len)) { | |||||
EVP_CIPHER_CTX_free(ctx); | |||||
return -1; | |||||
} | |||||
encrypted_len += len; | |||||
EVP_CIPHER_CTX_free(ctx); | |||||
return encrypted_len; | |||||
} | |||||
int lc6crypto_decrypt( | |||||
unsigned char *encrypted, | |||||
int encrypted_len, | |||||
unsigned char *data, | |||||
unsigned char *key, | |||||
unsigned char *iv) | |||||
{ | |||||
EVP_CIPHER_CTX *ctx; | |||||
int data_len = 0; | |||||
int len = 0; | |||||
if(!(ctx = EVP_CIPHER_CTX_new())) | |||||
return -1; | |||||
if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv)) { | |||||
EVP_CIPHER_CTX_free(ctx); | |||||
return -1; | |||||
} | |||||
if(1 != EVP_DecryptUpdate(ctx, data, &len, encrypted, encrypted_len)) { | |||||
EVP_CIPHER_CTX_free(ctx); | |||||
return -1; | |||||
} | |||||
data_len += len; | |||||
if(1 != EVP_DecryptFinal_ex(ctx, encrypted + len, &len)) { | |||||
EVP_CIPHER_CTX_free(ctx); | |||||
return -1; | |||||
} | |||||
data_len += len; | |||||
EVP_CIPHER_CTX_free(ctx); | |||||
return data_len; | |||||
} | |||||
int lc6crypto_random(unsigned char *data, int data_len) { | |||||
if ( ! lc6crypto_seeded ) { | |||||
RAND_poll(); | |||||
lc6crypto_seeded=1; | |||||
} | |||||
if ( RAND_bytes(data, data_len) != 1 ) | |||||
return -1; | |||||
return data_len; | |||||
} |
#include <stdio.h> | |||||
void lc6helpers_printhex(unsigned char *data, int data_len) { | |||||
int i; | |||||
for(i=0; i<data_len; i++) { | |||||
printf("%02x", data[i]); | |||||
} | |||||
} | |||||
void lc6helpers_banner(unsigned char *str) { | |||||
printf("\n"); | |||||
printf("################################################\n"); | |||||
printf("# %s\n", str); | |||||
printf("################################################\n"); | |||||
printf("\n"); | |||||
} |
#ifndef LC6_HELPERS_H | |||||
#define LC6_HELPERS_H | |||||
void lc6helpers_printhex(unsigned char*, int); | |||||
void lc6helpers_banner(unsigned char*); | |||||
#endif |
#include <string.h> | |||||
#include <stdlib.h> | |||||
#include <assert.h> | |||||
#include "lc6_crypto.h" | |||||
#include "lc6_node.h" | |||||
LC6_NODE* lc6node_create(void) { | |||||
LC6_NODE *node; | |||||
node = malloc(sizeof(LC6_NODE)); | |||||
assert(node); | |||||
memset(node, '\0', sizeof(LC6_NODE)); | |||||
return node; | |||||
} | |||||
void lc6node_free(LC6_NODE *node) { | |||||
if ( !node ) | |||||
return; | |||||
if ( node->pub_key ) | |||||
free(node->pub_key); | |||||
if ( node->priv_key ) | |||||
free(node->priv_key); | |||||
free(node); | |||||
} |
#ifndef LC6_NODE_H | |||||
#define LC6_NODE_H | |||||
typedef struct LC6_NODE { | |||||
unsigned char *pub_key; | |||||
unsigned char *priv_key; | |||||
} LC6_NODE; | |||||
LC6_NODE* lc6node_create(void); | |||||
void lc6node_free(LC6_NODE *node); | |||||
#endif |
#include <openssl/rsa.h> | |||||
#include <openssl/pem.h> | |||||
#include <string.h> | |||||
#include <assert.h> | |||||
#include "lc6_ssl.h" | |||||
libchat_user* ssl_create_keypair(libchat_user *user) { | |||||
BIGNUM *bn; | |||||
RSA *rsa; | |||||
BIO *pub; | |||||
BIO *priv; | |||||
size_t publen; | |||||
size_t privlen; | |||||
if ( user == NULL ) { | |||||
user = malloc(sizeof(&user)); | |||||
assert(user); | |||||
memset(user, 0, sizeof(&user)); | |||||
} | |||||
bn = BN_new(); | |||||
BN_set_word(bn, RSA_F4); | |||||
rsa = RSA_new(); | |||||
RSA_generate_key_ex(rsa, 2048, bn, NULL); | |||||
priv = BIO_new(BIO_s_mem()); | |||||
pub = BIO_new(BIO_s_mem()); | |||||
PEM_write_bio_RSAPrivateKey(priv, rsa, NULL, NULL, 0, NULL, NULL); | |||||
PEM_write_bio_RSAPublicKey(pub, rsa); | |||||
RSA_free(rsa); | |||||
privlen = BIO_pending(priv); | |||||
publen = BIO_pending(pub); | |||||
user->priv_key = malloc(privlen+1); | |||||
user->pub_key = malloc(publen+1); | |||||
BIO_read(priv, user->priv_key, privlen); | |||||
BIO_read(pub, user->pub_key, publen); | |||||
user->priv_key[privlen] = '\0'; | |||||
user->pub_key[publen] = '\0'; | |||||
BIO_free_all(priv); | |||||
BIO_free_all(pub); | |||||
BN_free(bn); | |||||
// RSA_free(rsa); | |||||
return user; | |||||
} |
#ifndef LC6_SSL_H | |||||
#define LC6_SSL_H | |||||
#include "libchat6.h" | |||||
libchat_user* ssl_create_keypair(libchat_user*); | |||||
#endif |
#include <stdio.h> | |||||
#include <stdlib.h> | |||||
#include "lc6_crypto.h" | |||||
#include "lc6_user.h" | |||||
LC6_USER* lc6user_create(void) { | |||||
LC6_USER *user = malloc(sizeof(LC6_USER)); | |||||
return lc6crypto_genuserkey(user); | |||||
} | |||||
void lc6user_free(LC6_USER *user) { | |||||
if ( !user ) | |||||
return; | |||||
if ( user->pub_key ) | |||||
free(user->pub_key); | |||||
if ( user->priv_key ) | |||||
free(user->priv_key); | |||||
if ( user->icon ) | |||||
free(user->icon); | |||||
if ( user->next ) | |||||
user->next->prev = user->prev; | |||||
if ( user->prev ) | |||||
user->prev->next = user->next; | |||||
free(user); | |||||
} |
#ifndef LC6_USER_H | |||||
#define LC6_USER_H | |||||
typedef struct LC6_USER { | |||||
struct LC6_USER *prev; | |||||
struct LC6_USER *next; | |||||
unsigned char nickname[256]; | |||||
unsigned char *pub_key; | |||||
unsigned char *priv_key; | |||||
unsigned char *icon; | |||||
unsigned int status; | |||||
} LC6_USER; | |||||
LC6_USER* lc6user_create(void); | |||||
void lc6user_free(LC6_USER *user); | |||||
#endif |
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <string.h> | |||||
#include <assert.h> | #include <assert.h> | ||||
#include "lc6_ssl.h" | |||||
#include "lc6_config.h" | |||||
LC6_CTX* libchat_init(unsigned char *password, char *path) { | |||||
int libchat_init(libchat_user *user) { | |||||
LC6_CTX *conf = lc6config_load(password, path); | |||||
if ( user == NULL ) | |||||
return LIBCHAT_ERROR_INPUT_NULL; | |||||
if ( !conf ) | |||||
return NULL; | |||||
return 0; | |||||
} | |||||
if ( !conf->user ) | |||||
conf->user = lc6user_create(); | |||||
libchat_user* libchat_create_user(libchat_user *user) { | |||||
return ssl_create_keypair(user); | |||||
return conf; | |||||
} | } | ||||
void libchat_free_user(libchat_user *user) { | |||||
if ( !user ) | |||||
return; | |||||
if ( user->pub_key ) | |||||
free(user->pub_key); | |||||
if ( user->priv_key ) | |||||
free(user->priv_key); | |||||
free(user); | |||||
} |
#ifndef LC6_LIBCHAT6_H | #ifndef LC6_LIBCHAT6_H | ||||
#define LC6_LIBCHAT6_H | #define LC6_LIBCHAT6_H | ||||
typedef struct libchat_user { | |||||
char nickname[256]; | |||||
char *pub_key; | |||||
char *priv_key; | |||||
char icon[32768]; | |||||
} libchat_user; | |||||
enum LIBCHAT_ERRORS { | |||||
LIBCHAT_ERROR_INPUT_NULL = 1 | |||||
enum LIBCHAR_USER_STATUS { | |||||
LC6_STATUS_OFFLINE = 0, | |||||
LC6_STATUS_ONLINE, | |||||
LC6_STATUS_AWAY, | |||||
LC6_STATUS_TYPING | |||||
}; | }; | ||||
int libchat_init(libchat_user*); | |||||
libchat_user* libchat_create_user(libchat_user*); | |||||
void libchat_free_user(libchat_user*); | |||||
typedef void *LIBCHAT; | |||||
LIBCHAT* libchat_init(unsigned char *password, char *path); | |||||
#endif | #endif |
#include <string.h> | #include <string.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <sodium.h> | |||||
#include "libchat6.h" | #include "libchat6.h" | ||||
#include "lc6_helpers.h" | |||||
#include "lc6_crypto.h" | |||||
#include "lc6_user.h" | |||||
int main(int argc, char **argv) { | int main(int argc, char **argv) { | ||||
libchat_user *user; | |||||
user = libchat_create_user(NULL); | |||||
unsigned char data[1024]; | |||||
unsigned char data2[1024]; | |||||
unsigned char *ptr_data = NULL; | |||||
unsigned char *ptr_data2 = NULL; | |||||
unsigned char *ptr_nonce = NULL; | |||||
int i, len; | |||||
LC6_USER *user; | |||||
lc6helpers_banner("Generating random bytes..."); | |||||
for(i=0; i<8; i++) { | |||||
printf("random bytes... "); | |||||
lc6crypto_random(data, 16); | |||||
lc6helpers_printhex(data, 16); | |||||
printf("\n"); | |||||
} | |||||
lc6helpers_banner("Generating SHA256 hashs..."); | |||||
for(i=0; i<8; i++) { | |||||
unsigned char *hash; | |||||
lc6crypto_random(data, 16); | |||||
hash = lc6crypto_hash(data, 16); | |||||
printf("random: "); | |||||
lc6helpers_printhex(data, 16); | |||||
printf(", hash: "); | |||||
lc6helpers_printhex(hash, 32); | |||||
printf("\n"); | |||||
free(hash); | |||||
} | |||||
lc6helpers_banner("Generating new user and keys..."); | |||||
user = lc6user_create(); | |||||
strcpy(user->nickname,"Päscu"); | strcpy(user->nickname,"Päscu"); | ||||
printf("pub\n%s\n", user->pub_key); | |||||
printf("priv\n%s\n", user->priv_key); | |||||
printf("Private key\n"); | |||||
lc6helpers_printhex(user->priv_key, crypto_box_SECRETKEYBYTES); | |||||
printf("\n"); | |||||
printf("Public key\n"); | |||||
lc6helpers_printhex(user->pub_key, crypto_box_PUBLICKEYBYTES); | |||||
lc6helpers_banner("Public key encrypt, private key decrypt"); | |||||
strcpy(data,"This is a test message to be encrypted. It may contain UTF-8 chars like 🤪"); | |||||
printf("plain data: %s\n", data); | |||||
len = lc6crypto_public_encrypt(data, strlen(data), user->priv_key, user->pub_key, &ptr_data, &ptr_nonce); | |||||
printf("encrypted : "); | |||||
lc6helpers_printhex(ptr_data, len); | |||||
printf("\n"); | |||||
len = lc6crypto_private_decrypt(ptr_data, len, user->priv_key, user->pub_key, &ptr_data, ptr_nonce); | |||||
printf("decrypted : %s\n", ptr_data); | |||||
free(ptr_data); | |||||
free(ptr_nonce); | |||||
free(ptr_data2); | |||||
lc6helpers_banner("Private key encrypt, public key decrypt"); | |||||
strcpy(data,"This is a test message to be encrypted. It may contain UTF-8 chars like 🤪"); | |||||
printf("plain data: %s\n", data); | |||||
len = lc6crypto_private_encrypt(data, strlen(data), user->priv_key, user->pub_key, &ptr_data, &ptr_nonce); | |||||
printf("encrypted : "); | |||||
lc6helpers_printhex(ptr_data, len); | |||||
printf("\n"); | |||||
len = lc6crypto_public_decrypt(ptr_data, len, user->priv_key, user->pub_key, &ptr_data, ptr_nonce); | |||||
printf("decrypted : %s\n", ptr_data); | |||||
free(ptr_data); | |||||
free(ptr_nonce); | |||||
free(ptr_data2); | |||||
libchat_free_user(user); | |||||
lc6user_free(user); | |||||
user = NULL; | user = NULL; | ||||
return 0; | return 0; |