@@ -30,3 +30,6 @@ install: | |||
uninstall: | |||
rm -f /usr/local/lib/libchat6.so | |||
test: | |||
$(MAKE) -C src test |
@@ -51,6 +51,13 @@ NOTE: All encrypted data is represented as base64. | |||
* neighbour: ipaddress,port | |||
* 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 | |||
``` | |||
@@ -66,10 +73,12 @@ NOTE: All encrypted data is represented as base64. | |||
<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 READ {target_hash, chatid, msgid} | |||
``` | |||
@@ -79,4 +88,4 @@ NOTE: All encrypted data is represented as base64. | |||
``` | |||
<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 | |||
``` | |||
``` |
@@ -18,12 +18,17 @@ CC := gcc | |||
#CCFLAGS := -fPIC -Wall -Werror -std=c11 -pedantic -O2 | |||
CCFLAGS := -fPIC -Wall -Werror -std=c11 -pedantic -g | |||
LDFLAGS := | |||
LIBS := -lchat6 -lssl -lpthread -lcrypto | |||
LIBS := -lchat6 -lssl -lpthread -lcrypto -lsodium | |||
TARGETS:= libchat6.so libchat6.a | |||
MAINS := $(.o, $(TARGETS) ) | |||
OBJ := \ | |||
lc6_ssl.o \ | |||
lc6_node.o \ | |||
lc6_config.o \ | |||
lc6_helpers.o \ | |||
lc6_user.o \ | |||
lc6_crypto.o \ | |||
lc6_base64.o \ | |||
libchat6.o \ | |||
$(MAINS) | |||
DEPS := | |||
@@ -46,5 +51,5 @@ libchat6.a: $(OBJ) | |||
ranlib $@ | |||
test: test.o | |||
$(CC) $(LDFLAGS) $^ -o $@ $(LIBS) | |||
$(CC) $(CCFLAGS) $(LDFLAGS) $^ -o $@ $(LIBS) | |||
@@ -0,0 +1,156 @@ | |||
/* | |||
* 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; | |||
} |
@@ -0,0 +1,8 @@ | |||
#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 | |||
@@ -0,0 +1,96 @@ | |||
#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++; | |||
} | |||
} | |||
} |
@@ -0,0 +1,40 @@ | |||
#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 |
@@ -0,0 +1,195 @@ | |||
#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); | |||
} |
@@ -0,0 +1,58 @@ | |||
#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 |
@@ -0,0 +1,217 @@ | |||
#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; | |||
} |
@@ -0,0 +1,19 @@ | |||
#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"); | |||
} |
@@ -0,0 +1,7 @@ | |||
#ifndef LC6_HELPERS_H | |||
#define LC6_HELPERS_H | |||
void lc6helpers_printhex(unsigned char*, int); | |||
void lc6helpers_banner(unsigned char*); | |||
#endif |
@@ -0,0 +1,29 @@ | |||
#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); | |||
} |
@@ -0,0 +1,12 @@ | |||
#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 |
@@ -1,56 +0,0 @@ | |||
#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; | |||
} |
@@ -1,8 +0,0 @@ | |||
#ifndef LC6_SSL_H | |||
#define LC6_SSL_H | |||
#include "libchat6.h" | |||
libchat_user* ssl_create_keypair(libchat_user*); | |||
#endif |
@@ -0,0 +1,33 @@ | |||
#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); | |||
} |
@@ -0,0 +1,18 @@ | |||
#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 |
@@ -1,31 +1,20 @@ | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.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); | |||
} |
@@ -1,19 +1,15 @@ | |||
#ifndef 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 |
@@ -2,19 +2,94 @@ | |||
#include <string.h> | |||
#include <stdlib.h> | |||
#include <sodium.h> | |||
#include "libchat6.h" | |||
#include "lc6_helpers.h" | |||
#include "lc6_crypto.h" | |||
#include "lc6_user.h" | |||
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"); | |||
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; | |||
return 0; |