aboutsummaryrefslogtreecommitdiff
path: root/transport.c
blob: fea3e7eae6d40295a784ecbfaee2cf2963db1a5c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#include <stdio.h>
#include <string.h>
#include <sodium.h>
#include "transport.h"
#include "net.h"

#define STREAM_KEY_SIZE 32
#define STREAM_HEADER_SIZE 24
#define PARTY_PUBKEY_SIZE 32
#define PARTY_SECKEY_SIZE 32


__attribute__((warn_unused_result))
static bool check_libsodium_size_assumptions(void) {
	return
		crypto_secretstream_xchacha20poly1305_KEYBYTES == STREAM_KEY_SIZE &&
		crypto_secretstream_xchacha20poly1305_HEADERBYTES == STREAM_HEADER_SIZE &&
		crypto_kx_SESSIONKEYBYTES >= STREAM_KEY_SIZE &&
		crypto_kx_PUBLICKEYBYTES == PARTY_PUBKEY_SIZE &&
		crypto_kx_SECRETKEYBYTES == PARTY_SECKEY_SIZE;
}

static void send_clienthello(
	int fd,
	const unsigned char pubkey[PARTY_PUBKEY_SIZE]
) {
	char buffer[16 + PARTY_PUBKEY_SIZE];
	memcpy(buffer, "tomsg v01 client", 16);
	memcpy(buffer + 16, pubkey, PARTY_PUBKEY_SIZE);
	net_send_raw_text(fd, buffer, sizeof buffer);
}

static void send_serverhello(
	int fd,
	const unsigned char pubkey[PARTY_PUBKEY_SIZE],
	const unsigned char server_tx_header[STREAM_HEADER_SIZE]
) {
	char buffer[16 + PARTY_PUBKEY_SIZE + STREAM_HEADER_SIZE];
	memcpy(buffer, "tomsg v01 server", 16);
	memcpy(buffer + 16, pubkey, PARTY_PUBKEY_SIZE);
	memcpy(buffer + 16 + PARTY_PUBKEY_SIZE, server_tx_header, STREAM_HEADER_SIZE);
	net_send_raw_text(fd, buffer, sizeof buffer);
}

static void send_clienthello2(
	int fd,
	const unsigned char client_tx_header[STREAM_HEADER_SIZE]
) {
	char buffer[8 + STREAM_HEADER_SIZE];
	memcpy(buffer, "cheader0", 8);
	memcpy(buffer + 8, client_tx_header, STREAM_HEADER_SIZE);
	net_send_raw_text(fd, buffer, sizeof buffer);
}


enum phase {
	WAITING_FOR_SERVERHELLO,
	WAITING_FOR_CLIENTHELLO,
	WAITING_FOR_CLIENTHELLO2,
	WAITING_FOR_DATA,  // handshake finished
};

struct transport {
	int fd;
	bool is_server;
	enum phase phase;
	unsigned char my_pubkey[PARTY_PUBKEY_SIZE];
	unsigned char my_seckey[PARTY_SECKEY_SIZE];
	unsigned char other_pubkey[PARTY_PUBKEY_SIZE];
	crypto_secretstream_xchacha20poly1305_state pushstate;
	crypto_secretstream_xchacha20poly1305_state pullstate;
};

struct transport* tsp_start(int fd, bool is_server) {
	if (!check_libsodium_size_assumptions()) {
		die("Transport protocol size assumptions do not hold!");
	}

	struct transport *tsp = calloc(1, struct transport);
	tsp->fd = fd;
	tsp->is_server = is_server;

	crypto_kx_keypair(tsp->my_pubkey, tsp->my_seckey);

	if (is_server) {
		tsp->phase = WAITING_FOR_CLIENTHELLO;
	} else {
		send_clienthello(fd, tsp->my_pubkey);
		tsp->phase = WAITING_FOR_SERVERHELLO;
	}

	return tsp;
}

void tsp_close(struct transport *tsp) {
	if (tsp->phase == WAITING_FOR_DATA) {

	}
}