1
0
Fork 0
tetatet/src/main.c

299 lines
7.7 KiB
C

#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include "addrbook.h"
#include "audio.h"
#include "crypt.h"
#include "net.h"
#define VERSION "0.0.0"
#define CHANNELS 1
#define SAMPLE_RATE 48000
#define FRAMES_PER_BUFFFER 960
#define AUDIO_BUF_SIZE (FRAMES_PER_BUFFFER * CHANNELS)
#define NET_BUF_SIZE 1024
int client_handshake(net_t *const n, crypt_session_t *const s, crypt_key_t *const ok, crypt_key_t *const rk);
int server_handshake(net_t *const n, crypt_session_t *const s, crypt_key_t *const ok, crypt_key_t *const rk);
struct options {
const char *addr;
const char *port;
const char *addressbook_path;
const char *key_path;
bool is_alias_passed;
char command;
};
int parse_argv(int argc, const char **argv, struct options *opts);
void usage(void) {
fprintf(stderr, "tetatet -vh c|s ADDR PORT -k KEY_PATH -a ADDRESSBOOK_FILE\n");
}
void version(void) {
fprintf(stdout,
"tetatet ver. " VERSION
"\nCopyright (c) Alexander \"Arav\" Andreev <me@arav.su>\n");
}
int main(int argc, const char **argv) {
int result = 0;
struct options opts = {0};
addrbook_t ab = {0};
net_t n = {0};
crypt_session_t s = {0};
crypt_key_t ok = {0}, rk = {0};
result = parse_argv(argc, argv, &opts);
switch (result) {
case -1: usage(); return 1;
case -2: version(); return 0;
case -3: usage(); return 0;
}
if (sodium_init() == -1) {
fprintf(stderr, "Cannot initialise libsodium.\n");
return 1;
}
// if (audio_init_soundsystem() == -1)
// return 1;
FILE *addrbook_file = fopen("addressbook", "r");
if (addrbook_file != NULL) {
addrbook_load(&ab, addrbook_file);
fclose(addrbook_file);
}
if (opts.is_alias_passed) {
addrbook_entry_t *aec = addrbook_get_by_alias(&ab, opts.addr);
if (aec == NULL) {
fprintf(stderr, "An alias \"%s\" is not in an addressbook!\n", opts.addr);
return 0;
} else {
fprintf(stderr, "An alias \"%s\" was found in an addressbook!\n", opts.addr);
opts.addr = aec->last_addr;
opts.port = aec->last_port;
}
}
FILE *pkey_file = fopen("tat_own_pub_key", "r");
FILE *skey_file = fopen("tat_own_sec_key", "r");
if (pkey_file == NULL || skey_file == NULL) {
if ((result = crypt_key_gen(&ok)) == -1) {
result = 1;
goto cleanup;
}
pkey_file = fopen("tat_own_pub_key", "w+");
skey_file = fopen("tat_own_sec_key", "w+");
crypt_store_key(&ok, pkey_file, skey_file);
fclose(pkey_file);
fclose(skey_file);
printf("A new cryptographical keys was written.\n");
} else {
if (crypt_load_key(&ok, pkey_file, skey_file) == -1) {
fprintf(stderr, "Cannot load the keys.");
result = 1;
goto cleanup;
}
if (pkey_file != NULL)
fclose(pkey_file);
if (skey_file != NULL)
fclose(skey_file);
}
(opts.command == 'c') ?
(result = net_client_init(&n, opts.addr, opts.port))
: (result = net_server_init(&n, opts.addr , opts.port));
if (result != 0)
goto cleanup;
(opts.command == 'c') ?
(result = client_handshake(&n, &s, &ok, &rk))
: (result = server_handshake(&n, &s, &ok, &rk));
if (result != 0)
goto cleanup;
char rkph[CRYPT_PKEY_HEXLEN];
crypt_key_export_public(&rk, rkph);
fprintf(stdout, "A connection with %s established!\n", rkph);
audio_t aud = {0};
unsigned char aud_buf[AUDIO_BUF_SIZE];
memset(aud_buf, 0, AUDIO_BUF_SIZE);
audio_init_default(&aud, CHANNELS, SAMPLE_RATE, FRAMES_PER_BUFFFER);
(opts.command == 'c') ?
(audio_stream_input_toggle(&aud))
: (audio_stream_output_toggle(&aud));
// for (size_t i = 0; i < (20 * SAMPLE_RATE)/FRAMES_PER_BUFFFER; ++i) {
// if (opts.command == 'c') {
// audio_read(&aud, aud_buf, AUDIO_BUF_SIZE);
// } else {
// //
// }
// }
(opts.command == 'c') ?
(audio_stream_input_toggle(&aud))
: (audio_stream_output_toggle(&aud));
cleanup:
addrbook_destroy(&ab);
audio_destroy(&aud);
net_destroy(&n);
crypt_session_destroy(&s);
crypt_key_destroy(&ok);
crypt_key_destroy(&rk);
if (audio_terminate_soundsystem() == -1)
return 1;
return result;
}
int handshake(const unsigned char * hello, const char * remote_hello, crypt_session_t *const s, crypt_key_t *const ok, crypt_key_t *const rk) {
unsigned char *nonce = NULL;
if (crypt_key_from_hex_public(rk, remote_hello) == -1)
return -1;
if (crypt_hello_verify((unsigned char *)remote_hello, rk) == -1)
return -2;
if ((nonce = crypt_hello_get_nonce(hello, (unsigned char *)remote_hello, true)) == NULL)
return -1;
if (crypt_session_init(s, ok, rk, nonce, true) == -1) {
free(nonce);
return -3;
}
free(nonce);
return 0;
}
int client_handshake(net_t *const n, crypt_session_t *const s, crypt_key_t *const ok, crypt_key_t *const rk) {
char buffer[NET_BUF_SIZE];
ssize_t bytes = 0;
unsigned char *hello = NULL;
if ((hello = crypt_hello(ok)) == NULL)
return -1;
if (net_send(n, (char *)hello, CRYPT_HELLO_LEN) == -1) {
free(hello);
return -1;
}
if ((bytes = net_recv(n, buffer, NET_BUF_SIZE)) == -1) {
free(hello);
return -1;
}
if (CRYPT_HELLO_LEN != bytes) {
free(hello);
return -1;
}
int res = handshake(hello, buffer, s, ok, rk);
free(hello);
return res;
}
int server_handshake(net_t *const n, crypt_session_t *const s, crypt_key_t *const ok, crypt_key_t *const rk) {
char buffer[NET_BUF_SIZE];
ssize_t bytes = 0;
unsigned char *hello = NULL;
if ((bytes = net_recv(n, buffer, NET_BUF_SIZE)) == -1)
return -1;
if (CRYPT_HELLO_LEN != bytes)
return -1;
if ((hello = crypt_hello(ok)) == NULL)
return -1;
int res = handshake(hello, buffer, s, ok, rk);
if (res != 0) {
free(hello);
return res;
}
n->raddr = n->inaddr;
n->raddr_len = n->inaddr_len;
if (net_send(n, (char *)hello, CRYPT_HELLO_LEN) == -1) {
free(hello);
return -1;
}
free(hello);
return 0;
}
int parse_argv(int argc, const char **argv, struct options *opts) {
if (argc == 1)
return -1;
int command_arg_num = 0;
for (int i = 1; i < argc; ++i) {
if (argv[i][0] == '-') {
switch (argv[i][1]) {
case 'k': opts->key_path = argv[i+1]; ++i; continue;
case 'a': opts->addressbook_path = argv[i+1]; ++i; continue;
case 'v': return -2;
case 'h': return -3;
default: return -1;
}
} else {
if (opts->command == 'c' || opts->command == 's') {
if (command_arg_num == 0)
opts->addr = argv[i];
else if (command_arg_num == 1)
opts->port = argv[i];
++command_arg_num;
} else {
switch (argv[i][0]) {
case 'c':
case 's':
opts->command = argv[i][0];
break;
default: return -1;
}
}
}
}
int r = inet_pton(AF_INET, opts->addr, NULL);
if (r == -1)
r = inet_pton(AF_INET6, opts->addr, NULL);
opts->is_alias_passed = r == 0;
if (opts->command == '\0' || opts->addr[0] == '\0'
|| (!opts->is_alias_passed && opts->port == NULL))
return -1;
return 0;
}