mirror of
https://github.com/outbackdingo/nDPId.git
synced 2026-01-27 10:19:45 +00:00
Modified crypto to support multiple peers (multiple sender / multiple receiver) per ncrypt context
Signed-off-by: Toni Uhlig <matzeton@googlemail.com>
This commit is contained in:
@@ -14,9 +14,13 @@ struct
|
||||
struct cmdarg listen_address;
|
||||
struct cmdarg local_private_key_file;
|
||||
struct cmdarg remote_public_key_file;
|
||||
struct cmdarg parse_json_lines;
|
||||
struct cmdarg quiet;
|
||||
} options = {.listen_address = CMDARG_STR("127.0.0.1:7443"),
|
||||
.local_private_key_file = CMDARG_STR(NULL),
|
||||
.remote_public_key_file = CMDARG_STR(NULL)};
|
||||
.remote_public_key_file = CMDARG_STR(NULL),
|
||||
.parse_json_lines = CMDARG_BOOL(0),
|
||||
.quiet = CMDARG_BOOL(0)};
|
||||
|
||||
struct confopt config_map[] = {CONFOPT(NULL, &options.listen_address),
|
||||
CONFOPT(NULL, &options.local_private_key_file),
|
||||
@@ -26,7 +30,6 @@ static void print_usage(char const * const arg0)
|
||||
{
|
||||
static char const usage[] =
|
||||
"Usage: %s "
|
||||
"\t \t"
|
||||
"[-l] [-L listen-address] [-k private-key-file] [-K public-key-file]\n"
|
||||
"\t \t"
|
||||
"[-h]\n\n"
|
||||
@@ -35,6 +38,8 @@ static void print_usage(char const * const arg0)
|
||||
"\t \t(encrypted) UDP packets sent by nDPId\n"
|
||||
"\t-k\tThe path to the local private X25519 key file (PEM format)\n"
|
||||
"\t-K\tThe path to the remote public X25519 key file (PEM format)\n"
|
||||
"\t-p\tParse decrypted JSON lines\n"
|
||||
"\t-q\tQuiet mode, print errors only\n"
|
||||
"\t-h\tthis\n";
|
||||
|
||||
fprintf(stderr, usage, arg0);
|
||||
@@ -44,7 +49,7 @@ static int parse_options(int argc, char ** argv)
|
||||
{
|
||||
int opt;
|
||||
|
||||
while ((opt = getopt(argc, argv, "lL:k:K:h")) != -1)
|
||||
while ((opt = getopt(argc, argv, "lL:k:K:pqh")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
@@ -60,6 +65,12 @@ static int parse_options(int argc, char ** argv)
|
||||
case 'K':
|
||||
set_cmdarg_string(&options.remote_public_key_file, optarg);
|
||||
break;
|
||||
case 'p':
|
||||
set_cmdarg_boolean(&options.parse_json_lines, 1);
|
||||
break;
|
||||
case 'q':
|
||||
set_cmdarg_boolean(&options.quiet, 1);
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
default:
|
||||
@@ -99,17 +110,44 @@ int udp_server(struct ncrypt * const nc)
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct ncrypt_buffer read_buf = {};
|
||||
size_t msgs_recvd = 0;
|
||||
char read_buffer[NCRYPT_BUFFER_SIZE];
|
||||
struct nDPIsrvd_json_buffer json_buf;
|
||||
struct nDPIsrvd_jsmn json_ctx;
|
||||
for (;;)
|
||||
{
|
||||
int bytes_read = ncrypt_decrypt_recv(nc, sock_fd, &read_buf);
|
||||
if (bytes_read <= 0)
|
||||
nDPIsrvd_json_buffer_reset(&json_buf);
|
||||
size_t read_buffer_size = sizeof(read_buffer);
|
||||
int ret = ncrypt_dgram_recv(nc, sock_fd, read_buffer, read_buffer_size);
|
||||
if (ret < 0)
|
||||
{
|
||||
logger(1, "Crypto error: %d", bytes_read);
|
||||
logger(1, "Crypto error: %d", ret);
|
||||
break;
|
||||
}
|
||||
msgs_recvd++;
|
||||
|
||||
printf("read %d bytes: %.*s", bytes_read, (int)read_buf.data_used, read_buf.plaintext.data);
|
||||
if (GET_CMDARG_BOOL(options.quiet) == 0)
|
||||
{
|
||||
printf("received: %.*s\n", (int)read_buffer_size, read_buffer);
|
||||
if ((msgs_recvd % 25) == 0)
|
||||
{
|
||||
printf("*** Messages received: %zu ***\n", msgs_recvd);
|
||||
}
|
||||
}
|
||||
|
||||
if (GET_CMDARG_BOOL(options.parse_json_lines) != 0)
|
||||
{
|
||||
json_buf.buf.ptr.raw = (uint8_t *)read_buffer;
|
||||
json_buf.buf.used = json_buf.buf.max = read_buffer_size;
|
||||
|
||||
enum nDPIsrvd_parse_return ret = nDPIsrvd_parse_line(&json_buf, &json_ctx);
|
||||
if (ret != PARSE_OK)
|
||||
{
|
||||
logger(1, "JSON parsing failed with: %d", ret);
|
||||
break;
|
||||
}
|
||||
json_ctx.tokens_found = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -174,12 +212,6 @@ int main(int argc, char ** argv)
|
||||
logger_early(1, "Crypto initialization failed: %d", ret);
|
||||
return 1;
|
||||
}
|
||||
ret = ncrypt_init_decrypt(&nc);
|
||||
if (ret != 0)
|
||||
{
|
||||
logger_early(1, "Crypto decrypt initialization failed: %d", ret);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return udp_server(&nc);
|
||||
|
||||
176
nDPId-test.c
176
nDPId-test.c
@@ -141,10 +141,10 @@ struct distributor_return_value
|
||||
};
|
||||
|
||||
#define TC_INIT(initial, wanted) \
|
||||
{ \
|
||||
.mutex = PTHREAD_MUTEX_INITIALIZER, .condition = PTHREAD_COND_INITIALIZER, .value = initial, \
|
||||
.wanted_value = wanted \
|
||||
}
|
||||
{.mutex = PTHREAD_MUTEX_INITIALIZER, \
|
||||
.condition = PTHREAD_COND_INITIALIZER, \
|
||||
.value = initial, \
|
||||
.wanted_value = wanted}
|
||||
struct thread_condition
|
||||
{
|
||||
pthread_mutex_t mutex;
|
||||
@@ -1647,11 +1647,19 @@ static int ncrypt_selftest()
|
||||
int ret = 0;
|
||||
struct ncrypt nc_peer1 = {};
|
||||
struct ncrypt nc_peer2 = {};
|
||||
struct aes aes_peer1 = {};
|
||||
struct aes aes_peer2 = {};
|
||||
unsigned char peer1_priv_key[NCRYPT_X25519_KEYLEN];
|
||||
unsigned char peer2_priv_key[NCRYPT_X25519_KEYLEN];
|
||||
unsigned char peer1_pub_key[NCRYPT_X25519_KEYLEN];
|
||||
unsigned char peer2_pub_key[NCRYPT_X25519_KEYLEN];
|
||||
unsigned char iv[NCRYPT_AES_IVLEN];
|
||||
char const plaintext[] = "Secret Message!";
|
||||
unsigned char encrypted[NCRYPT_BUFFER_SIZE];
|
||||
unsigned char tag[NCRYPT_TAG_SIZE];
|
||||
char decrypted[NCRYPT_BUFFER_SIZE];
|
||||
|
||||
memset(iv, 0x41, sizeof(iv));
|
||||
|
||||
if (ncrypt_keygen(peer1_priv_key, peer1_pub_key) != 0)
|
||||
{
|
||||
@@ -1669,176 +1677,74 @@ static int ncrypt_selftest()
|
||||
{
|
||||
ret++;
|
||||
}
|
||||
if (ncrypt_init_encrypt(&nc_peer1) != 0)
|
||||
if (ncrypt_init_encrypt(&nc_peer1, &aes_peer1) != 0)
|
||||
{
|
||||
ret++;
|
||||
}
|
||||
memcpy(&nc_peer2.iv, &nc_peer1.iv, sizeof(nc_peer1.iv));
|
||||
if (ncrypt_init_decrypt(&nc_peer2) != 0)
|
||||
if (ncrypt_init_decrypt(&nc_peer2, &aes_peer2) != 0)
|
||||
{
|
||||
ret++;
|
||||
}
|
||||
if (memcmp(nc_peer1.shared_secret, nc_peer2.shared_secret, NCRYPT_X25519_KEYLEN) != 0)
|
||||
int enc_bytes = ncrypt_encrypt(&aes_peer1, plaintext, sizeof(plaintext), iv, encrypted, tag);
|
||||
int dec_bytes = ncrypt_decrypt(&aes_peer2, encrypted, enc_bytes, iv, tag, decrypted);
|
||||
if (enc_bytes < 0 || dec_bytes < 0)
|
||||
{
|
||||
ret++;
|
||||
}
|
||||
if (memcmp(nc_peer1.iv, nc_peer2.iv, NCRYPT_AES_IVLEN) != 0)
|
||||
if (memcmp(plaintext, decrypted, sizeof(plaintext)) != 0)
|
||||
{
|
||||
ret++;
|
||||
}
|
||||
|
||||
memcpy(iv, nc_peer1.iv, NCRYPT_AES_IVLEN);
|
||||
unsigned char plaintext[] = "Secret Message";
|
||||
unsigned char encrypted1[NCRYPT_BUFFER_SIZE];
|
||||
unsigned char tag1[NCRYPT_TAG_SIZE];
|
||||
unsigned char encrypted2[NCRYPT_BUFFER_SIZE];
|
||||
unsigned char tag2[NCRYPT_TAG_SIZE];
|
||||
unsigned char tmp1[NETWORK_BUFFER_MAX_SIZE];
|
||||
unsigned char tmp2[NETWORK_BUFFER_MAX_SIZE];
|
||||
ncrypt_free_aes(&aes_peer2);
|
||||
ncrypt_free_aes(&aes_peer1);
|
||||
memset(decrypted, '\0', sizeof(decrypted));
|
||||
|
||||
memset(encrypted1, 0xFF, sizeof(encrypted1));
|
||||
memset(encrypted2, 0xFF, sizeof(encrypted2));
|
||||
memset(tag1, 0xFF, sizeof(tag1));
|
||||
memset(tag2, 0xFF, sizeof(tag2));
|
||||
|
||||
int enc_bytes;
|
||||
int dec_bytes;
|
||||
|
||||
enc_bytes = ncrypt_encrypt(&nc_peer1, plaintext, sizeof(plaintext), encrypted1, tag1);
|
||||
dec_bytes = ncrypt_decrypt(&nc_peer2, encrypted1, enc_bytes, tag1, tmp1);
|
||||
|
||||
if (enc_bytes != dec_bytes)
|
||||
struct nDPIsrvd_address listen_address;
|
||||
if (nDPIsrvd_setup_address(&listen_address, "127.0.0.1:17443") != 0)
|
||||
{
|
||||
ret++;
|
||||
}
|
||||
if (memcmp(plaintext, tmp1, dec_bytes) != 0)
|
||||
if (ncrypt_add_peer(&nc_peer1, &listen_address) != 0)
|
||||
{
|
||||
ret++;
|
||||
}
|
||||
memset(tmp1, 0xFF, sizeof(tmp1));
|
||||
|
||||
enc_bytes = ncrypt_encrypt(&nc_peer1, plaintext, sizeof(plaintext), encrypted2, tag2);
|
||||
dec_bytes = ncrypt_decrypt(&nc_peer2, encrypted2, enc_bytes, tag2, tmp1);
|
||||
|
||||
if (enc_bytes != dec_bytes)
|
||||
{
|
||||
ret++;
|
||||
}
|
||||
if (memcmp(plaintext, tmp1, dec_bytes) != 0)
|
||||
if (ncrypt_init_encrypt2(&nc_peer1, &listen_address) != 0)
|
||||
{
|
||||
ret++;
|
||||
}
|
||||
|
||||
if (memcmp(tag1, tag2, NCRYPT_TAG_SIZE) == 0)
|
||||
int udp_sockfd_listen = socket(listen_address.raw.sa_family, SOCK_DGRAM, 0);
|
||||
int udp_sockfd_connect = socket(listen_address.raw.sa_family, SOCK_DGRAM, 0);
|
||||
if (udp_sockfd_listen < 0 || udp_sockfd_connect < 0)
|
||||
{
|
||||
ret++;
|
||||
}
|
||||
if (memcmp(encrypted1, encrypted2, enc_bytes) == 0)
|
||||
if (bind(udp_sockfd_listen, &listen_address.raw, listen_address.size) != 0)
|
||||
{
|
||||
ret++;
|
||||
}
|
||||
if (connect(udp_sockfd_connect, &listen_address.raw, listen_address.size) < 0)
|
||||
{
|
||||
ret++;
|
||||
}
|
||||
|
||||
if (memcmp(iv, nc_peer1.iv, NCRYPT_AES_IVLEN) == 0)
|
||||
if (ncrypt_dgram_send(&nc_peer1, udp_sockfd_connect, plaintext, sizeof(plaintext)) != 0)
|
||||
{
|
||||
ret++;
|
||||
}
|
||||
if (ncrypt_dgram_recv(&nc_peer2, udp_sockfd_listen, decrypted, sizeof(decrypted)) != 0)
|
||||
{
|
||||
ret++;
|
||||
}
|
||||
|
||||
memset(encrypted1, 0xFF, sizeof(encrypted1));
|
||||
memset(tag1, 0xFF, sizeof(tag1));
|
||||
memset(tmp1, 0x41, sizeof(tmp1));
|
||||
enc_bytes = ncrypt_encrypt(&nc_peer1, tmp1, sizeof(tmp1), encrypted1, tag1);
|
||||
dec_bytes = ncrypt_decrypt(&nc_peer2, encrypted1, enc_bytes, tag1, tmp2);
|
||||
if (enc_bytes != sizeof(tmp1) || dec_bytes != sizeof(tmp2))
|
||||
{
|
||||
ret++;
|
||||
}
|
||||
if (memcmp(tmp1, tmp2, sizeof(tmp1)) != 0)
|
||||
if (memcmp(plaintext, decrypted, sizeof(plaintext)) != 0)
|
||||
{
|
||||
ret++;
|
||||
}
|
||||
|
||||
enc_bytes = ncrypt_encrypt(&nc_peer1, tmp1, sizeof(tmp1), encrypted2, tag2);
|
||||
dec_bytes = ncrypt_decrypt(&nc_peer2, encrypted2, enc_bytes, tag2, tmp2);
|
||||
if (enc_bytes != sizeof(tmp1) || dec_bytes != sizeof(tmp2))
|
||||
{
|
||||
ret++;
|
||||
}
|
||||
if (memcmp(tmp1, tmp2, sizeof(tmp1)) != 0)
|
||||
{
|
||||
ret++;
|
||||
}
|
||||
|
||||
if (enc_bytes != dec_bytes)
|
||||
{
|
||||
ret++;
|
||||
}
|
||||
if (memcmp(tmp2, encrypted1, dec_bytes) == 0)
|
||||
{
|
||||
ret++;
|
||||
}
|
||||
if (memcmp(tag1, tag2, NCRYPT_TAG_SIZE) == 0)
|
||||
{
|
||||
ret++;
|
||||
}
|
||||
if (memcmp(encrypted1, encrypted2, enc_bytes) == 0)
|
||||
{
|
||||
ret++;
|
||||
}
|
||||
if (memcmp(iv, nc_peer1.iv, NCRYPT_AES_IVLEN) == 0)
|
||||
{
|
||||
ret++;
|
||||
}
|
||||
if (memcmp(nc_peer1.iv, nc_peer2.iv, NCRYPT_AES_IVLEN) != 0)
|
||||
{
|
||||
ret++;
|
||||
}
|
||||
|
||||
int pipefds[2] = {-1, -1};
|
||||
if (pipe2(pipefds, O_DIRECT) != 0)
|
||||
{
|
||||
ret++;
|
||||
}
|
||||
|
||||
struct ncrypt_buffer encrypted_buf = {};
|
||||
struct ncrypt_buffer decrypted_buf = {};
|
||||
memcpy(encrypted_buf.plaintext.data, plaintext, sizeof(plaintext));
|
||||
encrypted_buf.data_used = sizeof(plaintext);
|
||||
|
||||
int sent;
|
||||
sent = ncrypt_encrypt_send(&nc_peer1, pipefds[1], &encrypted_buf);
|
||||
if (sent < 0)
|
||||
{
|
||||
ret++;
|
||||
}
|
||||
|
||||
int received = ncrypt_decrypt_recv(&nc_peer2, pipefds[0], &decrypted_buf);
|
||||
if (received < 0)
|
||||
{
|
||||
ret++;
|
||||
}
|
||||
|
||||
if (received != sent)
|
||||
{
|
||||
ret++;
|
||||
}
|
||||
|
||||
sent = ncrypt_encrypt_send(&nc_peer1, pipefds[1], &encrypted_buf);
|
||||
int sent2 = ncrypt_encrypt_send(&nc_peer1, pipefds[1], &encrypted_buf);
|
||||
if (sent < 0 || sent != sent2)
|
||||
{
|
||||
ret++;
|
||||
}
|
||||
|
||||
received = ncrypt_decrypt_recv(&nc_peer2, pipefds[0], &decrypted_buf);
|
||||
int received2 = ncrypt_decrypt_recv(&nc_peer2, pipefds[0], &decrypted_buf);
|
||||
if (received < 0 || received != received2)
|
||||
{
|
||||
ret++;
|
||||
}
|
||||
|
||||
close(pipefds[0]);
|
||||
close(pipefds[1]);
|
||||
|
||||
close(udp_sockfd_listen);
|
||||
close(udp_sockfd_connect);
|
||||
ncrypt_free(&nc_peer2);
|
||||
ncrypt_free(&nc_peer1);
|
||||
|
||||
|
||||
21
nDPId.c
21
nDPId.c
@@ -1618,7 +1618,14 @@ static struct nDPId_workflow * init_workflow(char const * const file_or_device)
|
||||
free_workflow(&workflow);
|
||||
return NULL;
|
||||
}
|
||||
rv = ncrypt_init_encrypt(&workflow->crypto);
|
||||
rv = ncrypt_add_peer(&workflow->crypto, &nDPId_options.parsed_collector_address);
|
||||
if (rv != 0)
|
||||
{
|
||||
logger(1, "Could not add peer: %d", rv);
|
||||
free_workflow(&workflow);
|
||||
return NULL;
|
||||
}
|
||||
rv = ncrypt_init_encrypt2(&workflow->crypto, &nDPId_options.parsed_collector_address);
|
||||
if (rv != 0)
|
||||
{
|
||||
logger_early(1, "Could not init encryption mode: %d", rv);
|
||||
@@ -2691,18 +2698,18 @@ static void send_to_collector(struct nDPId_reader_thread * const reader_thread,
|
||||
IS_CMDARG_SET(nDPId_options.remote_public_key_file) != 0)
|
||||
{
|
||||
int rv;
|
||||
struct ncrypt_buffer buf = {.data_used = s_ret};
|
||||
|
||||
memcpy(buf.plaintext.data, newline_json_msg, s_ret);
|
||||
rv = ncrypt_encrypt_send(&workflow->crypto, reader_thread->collector_sockfd, &buf);
|
||||
if (rv - (NCRYPT_AES_IVLEN + NCRYPT_TAG_SIZE) != s_ret)
|
||||
errno = 0;
|
||||
rv = ncrypt_dgram_send(&workflow->crypto, reader_thread->collector_sockfd, newline_json_msg, (size_t)s_ret);
|
||||
if (rv != 0)
|
||||
{
|
||||
logger(1,
|
||||
"[%8llu, %zu] Crypto: encrypt and send returned %d, but expected %d",
|
||||
"[%8llu, %zu] Crypto: encrypt and send returned %d (buffer size %d): %s",
|
||||
workflow->packets_captured,
|
||||
reader_thread->array_index,
|
||||
rv,
|
||||
s_ret + (NCRYPT_AES_IVLEN + NCRYPT_TAG_SIZE));
|
||||
s_ret,
|
||||
strerror(errno));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
477
ncrypt.c
477
ncrypt.c
@@ -6,12 +6,14 @@
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define OPENSSL_DUMP(ptr, siz) \
|
||||
do \
|
||||
{ \
|
||||
fprintf(stderr, "Raw output (%s, %zu):\n", #ptr, siz); \
|
||||
BIO_dump_indent_fp(stderr, ptr, siz, 2); \
|
||||
fputc('\n', stderr); \
|
||||
} while (0);
|
||||
@@ -31,6 +33,73 @@ union iv
|
||||
unsigned char buffer[NCRYPT_AES_IVLEN];
|
||||
};
|
||||
|
||||
union packet
|
||||
{
|
||||
unsigned char raw[NCRYPT_PACKET_BUFFER_SIZE];
|
||||
struct
|
||||
{
|
||||
unsigned char iv[NCRYPT_AES_IVLEN];
|
||||
unsigned char tag[NCRYPT_TAG_SIZE];
|
||||
unsigned char data[NCRYPT_BUFFER_SIZE];
|
||||
} __attribute__((__packed__));
|
||||
} __attribute__((__packed__));
|
||||
|
||||
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
|
||||
_Static_assert(sizeof(((union iv *)0)->buffer) == sizeof(((union iv *)0)->numeric),
|
||||
"IV buffer must be of the same size as the numerics");
|
||||
#endif
|
||||
|
||||
static inline nDPIsrvd_hashkey peer_build_hashkey(struct nDPIsrvd_address const * const peer_address)
|
||||
{
|
||||
uint32_t hash = nDPIsrvd_HASHKEY_SEED;
|
||||
|
||||
socklen_t slen = peer_address->size;
|
||||
while (slen-- > 0)
|
||||
{
|
||||
hash = ((hash << 5) + hash) + ((uint8_t *)&peer_address->raw)[slen];
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
int ncrypt_add_peer(struct ncrypt * const nc, struct nDPIsrvd_address const * const peer_address)
|
||||
{
|
||||
nDPIsrvd_hashkey peer_key = peer_build_hashkey(peer_address);
|
||||
if (peer_key == nDPIsrvd_HASHKEY_SEED)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct peer * peer = (struct peer *)calloc(1, sizeof(*peer));
|
||||
if (peer == NULL)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
peer->hash_key = peer_key;
|
||||
peer->address = *peer_address;
|
||||
HASH_ADD_INT(nc->peers, hash_key, peer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct peer * ncrypt_get_peer(struct ncrypt * const nc, struct nDPIsrvd_address const * const peer_address)
|
||||
{
|
||||
nDPIsrvd_hashkey peer_key = peer_build_hashkey(peer_address);
|
||||
if (peer_key == nDPIsrvd_HASHKEY_SEED)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct peer * peer;
|
||||
HASH_FIND_INT(nc->peers, &peer_key, peer);
|
||||
if (peer == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return peer;
|
||||
}
|
||||
|
||||
int ncrypt_keygen(unsigned char priv_key[NCRYPT_X25519_KEYLEN], unsigned char pub_key[NCRYPT_X25519_KEYLEN])
|
||||
{
|
||||
EVP_PKEY * const pkey = EVP_PKEY_Q_keygen(NULL, NULL, "X25519");
|
||||
@@ -109,7 +178,7 @@ int ncrypt_load_pubkey(char const * const public_key_file, unsigned char pub_key
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int init_iv(struct ncrypt * const nc)
|
||||
static int init_iv(struct peer * const peer)
|
||||
{
|
||||
FILE * rnd_fp;
|
||||
|
||||
@@ -120,7 +189,7 @@ static int init_iv(struct ncrypt * const nc)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fread(&nc->iv[0], sizeof(nc->iv[0]), sizeof(nc->iv) / sizeof(nc->iv[0]), rnd_fp) != NCRYPT_AES_IVLEN)
|
||||
if (fread(&peer->iv[0], sizeof(peer->iv[0]), sizeof(peer->iv) / sizeof(peer->iv[0]), rnd_fp) != NCRYPT_AES_IVLEN)
|
||||
{
|
||||
fclose(rnd_fp);
|
||||
return -2;
|
||||
@@ -131,9 +200,9 @@ static int init_iv(struct ncrypt * const nc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void next_iv(struct ncrypt * const nc)
|
||||
static void next_iv(struct peer * const peer)
|
||||
{
|
||||
union iv * const iv = (union iv *)&nc->iv[0];
|
||||
union iv * const iv = (union iv *)&peer->iv[0];
|
||||
|
||||
uint64_t lower = be64toh(iv->numeric.lower);
|
||||
lower++;
|
||||
@@ -151,9 +220,19 @@ int ncrypt_init(struct ncrypt * const nc,
|
||||
unsigned char local_priv_key[NCRYPT_X25519_KEYLEN],
|
||||
unsigned char remote_pub_key[NCRYPT_X25519_KEYLEN])
|
||||
{
|
||||
EVP_PKEY_CTX * key_ctx;
|
||||
int rv = 0;
|
||||
EVP_PKEY_CTX * key_ctx = NULL;
|
||||
size_t pub_key_datalen = 0;
|
||||
size_t secret_len = 0;
|
||||
struct
|
||||
{
|
||||
EVP_PKEY * priv_key;
|
||||
unsigned char pub_key[NCRYPT_X25519_KEYLEN];
|
||||
} local = {.priv_key = NULL, .pub_key = {}};
|
||||
struct
|
||||
{
|
||||
EVP_PKEY * pub_key;
|
||||
} remote = {.pub_key = NULL};
|
||||
|
||||
if (nc->libctx != NULL)
|
||||
{
|
||||
@@ -165,112 +244,143 @@ int ncrypt_init(struct ncrypt * const nc,
|
||||
return -2;
|
||||
}
|
||||
|
||||
nc->local.priv_key =
|
||||
local.priv_key =
|
||||
EVP_PKEY_new_raw_private_key_ex(nc->libctx, "X25519", nc->propq, local_priv_key, NCRYPT_X25519_KEYLEN);
|
||||
if (nc->local.priv_key == NULL)
|
||||
if (local.priv_key == NULL)
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
|
||||
if (EVP_PKEY_get_octet_string_param(nc->local.priv_key,
|
||||
OSSL_PKEY_PARAM_PUB_KEY,
|
||||
nc->local.pub_key,
|
||||
sizeof(nc->local.pub_key),
|
||||
&pub_key_datalen) == 0)
|
||||
if (EVP_PKEY_get_octet_string_param(
|
||||
local.priv_key, OSSL_PKEY_PARAM_PUB_KEY, local.pub_key, sizeof(local.pub_key), &pub_key_datalen) == 0)
|
||||
{
|
||||
return -4;
|
||||
rv = -4;
|
||||
goto error;
|
||||
}
|
||||
if (pub_key_datalen != NCRYPT_X25519_KEYLEN)
|
||||
{
|
||||
return -5;
|
||||
rv = -5;
|
||||
goto error;
|
||||
}
|
||||
|
||||
nc->remote.pub_key =
|
||||
remote.pub_key =
|
||||
EVP_PKEY_new_raw_public_key_ex(nc->libctx, "X25519", nc->propq, remote_pub_key, NCRYPT_X25519_KEYLEN);
|
||||
if (nc->remote.pub_key == NULL)
|
||||
if (remote.pub_key == NULL)
|
||||
{
|
||||
return -6;
|
||||
rv = -6;
|
||||
goto error;
|
||||
}
|
||||
|
||||
key_ctx = EVP_PKEY_CTX_new_from_pkey(nc->libctx, nc->local.priv_key, nc->propq);
|
||||
key_ctx = EVP_PKEY_CTX_new_from_pkey(nc->libctx, local.priv_key, nc->propq);
|
||||
if (key_ctx == NULL)
|
||||
{
|
||||
return -7;
|
||||
rv = -7;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (EVP_PKEY_derive_init(key_ctx) == 0)
|
||||
{
|
||||
EVP_PKEY_CTX_free(key_ctx);
|
||||
return -8;
|
||||
rv = -8;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (EVP_PKEY_derive_set_peer(key_ctx, nc->remote.pub_key) == 0)
|
||||
if (EVP_PKEY_derive_set_peer(key_ctx, remote.pub_key) == 0)
|
||||
{
|
||||
EVP_PKEY_CTX_free(key_ctx);
|
||||
return -9;
|
||||
rv = -9;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (EVP_PKEY_derive(key_ctx, NULL, &secret_len) == 0)
|
||||
{
|
||||
EVP_PKEY_CTX_free(key_ctx);
|
||||
return -10;
|
||||
rv = -10;
|
||||
goto error;
|
||||
}
|
||||
if (secret_len != NCRYPT_X25519_KEYLEN)
|
||||
{
|
||||
EVP_PKEY_CTX_free(key_ctx);
|
||||
return -11;
|
||||
rv = -11;
|
||||
goto error;
|
||||
}
|
||||
|
||||
nc->shared_secret = OPENSSL_malloc(secret_len);
|
||||
if (nc->shared_secret == NULL)
|
||||
{
|
||||
EVP_PKEY_CTX_free(key_ctx);
|
||||
return -12;
|
||||
}
|
||||
if (EVP_PKEY_derive(key_ctx, nc->shared_secret, &secret_len) == 0)
|
||||
{
|
||||
EVP_PKEY_CTX_free(key_ctx);
|
||||
OPENSSL_clear_free(nc->shared_secret, secret_len);
|
||||
nc->shared_secret = NULL;
|
||||
return -13;
|
||||
rv = -12;
|
||||
OPENSSL_cleanse(nc->shared_secret, NCRYPT_X25519_KEYLEN);
|
||||
goto error;
|
||||
}
|
||||
|
||||
nc->iv_mismatches = 0;
|
||||
|
||||
OPENSSL_cleanse(local_priv_key, NCRYPT_X25519_KEYLEN);
|
||||
OPENSSL_cleanse(remote_pub_key, NCRYPT_X25519_KEYLEN);
|
||||
|
||||
error:
|
||||
EVP_PKEY_CTX_free(key_ctx);
|
||||
return 0;
|
||||
EVP_PKEY_free(local.priv_key);
|
||||
EVP_PKEY_free(remote.pub_key);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int ncrypt_init_encrypt(struct ncrypt * const nc)
|
||||
int ncrypt_init_encrypt(struct ncrypt * const nc, struct aes * const aes)
|
||||
{
|
||||
if (nc->aesctx == NULL)
|
||||
aes->ctx = EVP_CIPHER_CTX_new();
|
||||
if (aes->ctx == NULL)
|
||||
{
|
||||
nc->aesctx = EVP_CIPHER_CTX_new();
|
||||
if (nc->aesctx == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (EVP_EncryptInit_ex(nc->aesctx, EVP_aes_256_gcm(), NULL, NULL, NULL) == 0)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (EVP_CIPHER_CTX_ctrl(nc->aesctx, EVP_CTRL_GCM_SET_IVLEN, NCRYPT_AES_IVLEN, NULL) == 0)
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
return -3;
|
||||
}
|
||||
|
||||
if (init_iv(nc) != 0)
|
||||
if (EVP_EncryptInit_ex(aes->ctx, EVP_aes_256_gcm(), NULL, NULL, NULL) == 0)
|
||||
{
|
||||
return -4;
|
||||
}
|
||||
|
||||
if (EVP_EncryptInit_ex(nc->aesctx, NULL, NULL, nc->shared_secret, nc->iv) == 0)
|
||||
if (EVP_CIPHER_CTX_ctrl(aes->ctx, EVP_CTRL_GCM_SET_IVLEN, NCRYPT_AES_IVLEN, NULL) == 0)
|
||||
{
|
||||
return -5;
|
||||
}
|
||||
|
||||
if (EVP_EncryptInit_ex(aes->ctx, NULL, NULL, nc->shared_secret, NULL) == 0)
|
||||
{
|
||||
return -6;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ncrypt_init_encrypt2(struct ncrypt * const nc, struct nDPIsrvd_address * const peer_address)
|
||||
{
|
||||
struct peer * const peer = ncrypt_get_peer(nc, peer_address);
|
||||
|
||||
if (peer == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (init_iv(peer) != 0)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
return ncrypt_init_encrypt(nc, &peer->aes);
|
||||
}
|
||||
|
||||
int ncrypt_init_decrypt(struct ncrypt * const nc, struct aes * const aes)
|
||||
{
|
||||
aes->ctx = EVP_CIPHER_CTX_new();
|
||||
if (aes->ctx == NULL)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (EVP_DecryptInit_ex(aes->ctx, EVP_aes_256_gcm(), NULL, NULL, NULL) == 0)
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
|
||||
if (EVP_CIPHER_CTX_ctrl(aes->ctx, EVP_CTRL_GCM_SET_IVLEN, NCRYPT_AES_IVLEN, NULL) == 0)
|
||||
{
|
||||
return -4;
|
||||
}
|
||||
|
||||
if (EVP_DecryptInit_ex(aes->ctx, NULL, NULL, nc->shared_secret, NULL) == 0)
|
||||
{
|
||||
return -5;
|
||||
}
|
||||
@@ -278,93 +388,81 @@ int ncrypt_init_encrypt(struct ncrypt * const nc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ncrypt_init_decrypt(struct ncrypt * const nc)
|
||||
int ncrypt_init_decrypt2(struct ncrypt * const nc, struct nDPIsrvd_address * const peer_address)
|
||||
{
|
||||
if (nc->aesctx == NULL)
|
||||
struct peer * const peer = ncrypt_get_peer(nc, peer_address);
|
||||
|
||||
if (peer == NULL)
|
||||
{
|
||||
nc->aesctx = EVP_CIPHER_CTX_new();
|
||||
if (nc->aesctx == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (EVP_DecryptInit_ex(nc->aesctx, EVP_aes_256_gcm(), NULL, NULL, NULL) == 0)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (EVP_CIPHER_CTX_ctrl(nc->aesctx, EVP_CTRL_GCM_SET_IVLEN, NCRYPT_AES_IVLEN, NULL) == 0)
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (EVP_DecryptInit_ex(nc->aesctx, NULL, NULL, nc->shared_secret, nc->iv) == 0)
|
||||
return ncrypt_init_decrypt(nc, &peer->aes);
|
||||
}
|
||||
|
||||
void ncrypt_free_aes(struct aes * const aes)
|
||||
{
|
||||
EVP_CIPHER_CTX_free(aes->ctx);
|
||||
aes->ctx = NULL;
|
||||
}
|
||||
|
||||
static void cleanup_peers(struct ncrypt * const nc)
|
||||
{
|
||||
struct peer * current_peer;
|
||||
struct peer * ctmp;
|
||||
|
||||
if (nc->peers == NULL)
|
||||
{
|
||||
return -4;
|
||||
return;
|
||||
}
|
||||
|
||||
return 0;
|
||||
HASH_ITER(hh, nc->peers, current_peer, ctmp)
|
||||
{
|
||||
ncrypt_free_aes(¤t_peer->aes);
|
||||
HASH_DEL(nc->peers, current_peer);
|
||||
free(current_peer);
|
||||
}
|
||||
}
|
||||
|
||||
void ncrypt_free(struct ncrypt * const nc)
|
||||
{
|
||||
if (nc->aesctx != NULL)
|
||||
{
|
||||
EVP_CIPHER_CTX_free(nc->aesctx);
|
||||
nc->aesctx = NULL;
|
||||
}
|
||||
|
||||
if (nc->shared_secret != NULL)
|
||||
{
|
||||
OPENSSL_clear_free(nc->shared_secret, NCRYPT_X25519_KEYLEN);
|
||||
nc->shared_secret = NULL;
|
||||
}
|
||||
|
||||
if (nc->local.priv_key != NULL)
|
||||
{
|
||||
EVP_PKEY_free(nc->local.priv_key);
|
||||
nc->local.priv_key = NULL;
|
||||
}
|
||||
|
||||
if (nc->remote.pub_key != NULL)
|
||||
{
|
||||
EVP_PKEY_free(nc->remote.pub_key);
|
||||
nc->remote.pub_key = NULL;
|
||||
}
|
||||
OPENSSL_cleanse(nc->shared_secret, NCRYPT_X25519_KEYLEN);
|
||||
|
||||
if (nc->libctx != NULL)
|
||||
{
|
||||
OSSL_LIB_CTX_free(nc->libctx);
|
||||
nc->libctx = NULL;
|
||||
}
|
||||
|
||||
cleanup_peers(nc);
|
||||
}
|
||||
|
||||
static int encrypt(struct ncrypt * const nc,
|
||||
unsigned char const * const plaintext,
|
||||
size_t used,
|
||||
static int encrypt(struct aes * const aes,
|
||||
char const * const plaintext,
|
||||
size_t plaintext_size,
|
||||
unsigned char const iv[NCRYPT_AES_IVLEN],
|
||||
unsigned char encrypted[NCRYPT_BUFFER_SIZE],
|
||||
unsigned char tag[NCRYPT_TAG_SIZE])
|
||||
{
|
||||
int encrypted_used;
|
||||
int remaining;
|
||||
|
||||
if (EVP_EncryptInit_ex(nc->aesctx, NULL, NULL, NULL, nc->iv) == 0)
|
||||
if (EVP_EncryptInit_ex(aes->ctx, NULL, NULL, NULL, iv) == 0)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (EVP_EncryptUpdate(nc->aesctx, encrypted, &encrypted_used, plaintext, used) == 0)
|
||||
if (EVP_EncryptUpdate(aes->ctx, encrypted, &encrypted_used, (const unsigned char *)plaintext, plaintext_size) == 0)
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
|
||||
if (EVP_EncryptFinal_ex(nc->aesctx, encrypted + encrypted_used, &remaining) == 0)
|
||||
if (EVP_EncryptFinal_ex(aes->ctx, encrypted + encrypted_used, &remaining) == 0)
|
||||
{
|
||||
return -4;
|
||||
}
|
||||
|
||||
if (EVP_CIPHER_CTX_ctrl(nc->aesctx, EVP_CTRL_GCM_GET_TAG, NCRYPT_TAG_SIZE, tag) == 0)
|
||||
if (EVP_CIPHER_CTX_ctrl(aes->ctx, EVP_CTRL_GCM_GET_TAG, NCRYPT_TAG_SIZE, tag) == 0)
|
||||
{
|
||||
return -5;
|
||||
}
|
||||
@@ -372,47 +470,47 @@ static int encrypt(struct ncrypt * const nc,
|
||||
return encrypted_used + remaining;
|
||||
}
|
||||
|
||||
int ncrypt_encrypt(struct ncrypt * const nc,
|
||||
unsigned char const * const plaintext,
|
||||
size_t used,
|
||||
int ncrypt_encrypt(struct aes * const aes,
|
||||
char const * const plaintext,
|
||||
size_t plaintext_size,
|
||||
unsigned char const iv[NCRYPT_AES_IVLEN],
|
||||
unsigned char encrypted[NCRYPT_BUFFER_SIZE],
|
||||
unsigned char tag[NCRYPT_TAG_SIZE])
|
||||
{
|
||||
if (used > NCRYPT_BUFFER_SIZE)
|
||||
if (plaintext_size > NCRYPT_BUFFER_SIZE)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
next_iv(nc);
|
||||
|
||||
return encrypt(nc, plaintext, used, encrypted, tag);
|
||||
return encrypt(aes, plaintext, plaintext_size, iv, encrypted, tag);
|
||||
}
|
||||
|
||||
int decrypt(struct ncrypt * const nc,
|
||||
unsigned char const * const encrypted,
|
||||
size_t used,
|
||||
unsigned char tag[NCRYPT_TAG_SIZE],
|
||||
unsigned char plaintext[NCRYPT_BUFFER_SIZE])
|
||||
static int decrypt(struct aes * const aes,
|
||||
unsigned char const * const encrypted,
|
||||
size_t encrypt_size,
|
||||
unsigned char const iv[NCRYPT_AES_IVLEN],
|
||||
unsigned char tag[NCRYPT_TAG_SIZE],
|
||||
char plaintext[NCRYPT_BUFFER_SIZE])
|
||||
{
|
||||
int decrypted_used;
|
||||
int remaining;
|
||||
|
||||
if (EVP_DecryptInit_ex(nc->aesctx, NULL, NULL, NULL, nc->iv) == 0)
|
||||
if (EVP_DecryptInit_ex(aes->ctx, NULL, NULL, NULL, iv) == 0)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (EVP_DecryptUpdate(nc->aesctx, plaintext, &decrypted_used, encrypted, used) == 0)
|
||||
if (EVP_DecryptUpdate(aes->ctx, (unsigned char *)plaintext, &decrypted_used, encrypted, encrypt_size) == 0)
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
|
||||
if (EVP_CIPHER_CTX_ctrl(nc->aesctx, EVP_CTRL_GCM_SET_TAG, NCRYPT_TAG_SIZE, tag) == 0)
|
||||
if (EVP_CIPHER_CTX_ctrl(aes->ctx, EVP_CTRL_GCM_SET_TAG, NCRYPT_TAG_SIZE, tag) == 0)
|
||||
{
|
||||
return -4;
|
||||
}
|
||||
|
||||
if (EVP_DecryptFinal_ex(nc->aesctx, plaintext + decrypted_used, &remaining) == 0)
|
||||
if (EVP_DecryptFinal_ex(aes->ctx, (unsigned char *)plaintext + decrypted_used, &remaining) == 0)
|
||||
{
|
||||
return -5;
|
||||
}
|
||||
@@ -420,78 +518,117 @@ int decrypt(struct ncrypt * const nc,
|
||||
return decrypted_used + remaining;
|
||||
}
|
||||
|
||||
int ncrypt_decrypt(struct ncrypt * const nc,
|
||||
int ncrypt_decrypt(struct aes * const aes,
|
||||
unsigned char const * const encrypted,
|
||||
size_t used,
|
||||
size_t encrypt_size,
|
||||
unsigned char const iv[NCRYPT_AES_IVLEN],
|
||||
unsigned char tag[NCRYPT_TAG_SIZE],
|
||||
unsigned char plaintext[NCRYPT_BUFFER_SIZE])
|
||||
char plaintext[NCRYPT_BUFFER_SIZE])
|
||||
{
|
||||
if (used > NCRYPT_BUFFER_SIZE)
|
||||
if (encrypt_size > NCRYPT_BUFFER_SIZE)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
next_iv(nc);
|
||||
|
||||
return decrypt(nc, encrypted, used, tag, plaintext);
|
||||
return decrypt(aes, encrypted, encrypt_size, iv, tag, plaintext);
|
||||
}
|
||||
|
||||
int ncrypt_encrypt_send(struct ncrypt * const nc, int fd, struct ncrypt_buffer * const buf)
|
||||
int ncrypt_dgram_send(struct ncrypt * const nc, int fd, char const * const plaintext, size_t plaintext_size)
|
||||
{
|
||||
int encrypted_used = encrypt(nc, buf->plaintext.data, buf->data_used, buf->encrypted.data, buf->encrypted.tag);
|
||||
if (encrypted_used < 0)
|
||||
if (plaintext_size > NCRYPT_BUFFER_SIZE)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(buf->encrypted.iv, nc->iv, NCRYPT_AES_IVLEN);
|
||||
ssize_t bytes_written = write(fd, buf->encrypted.raw, NCRYPT_AES_IVLEN + NCRYPT_TAG_SIZE + encrypted_used);
|
||||
next_iv(nc);
|
||||
int retval = 0;
|
||||
struct peer * current_peer;
|
||||
struct peer * tmp_peer;
|
||||
union packet encrypted;
|
||||
HASH_ITER(hh, nc->peers, current_peer, tmp_peer)
|
||||
{
|
||||
int encrypted_used =
|
||||
encrypt(¤t_peer->aes, plaintext, plaintext_size, current_peer->iv, encrypted.data, encrypted.tag);
|
||||
if (encrypted_used < 0 || encrypted_used > (int)NCRYPT_BUFFER_SIZE)
|
||||
{
|
||||
current_peer->crypto_errors++;
|
||||
retval++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bytes_written < 0)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
if (bytes_written != NCRYPT_AES_IVLEN + NCRYPT_TAG_SIZE + encrypted_used)
|
||||
{
|
||||
nc->partial_writes++;
|
||||
buf->write_offset += bytes_written;
|
||||
memcpy(encrypted.iv, current_peer->iv, NCRYPT_AES_IVLEN);
|
||||
ssize_t bytes_written = sendto(fd,
|
||||
encrypted.raw,
|
||||
NCRYPT_PACKET_OVERHEAD + encrypted_used,
|
||||
0,
|
||||
¤t_peer->address.raw,
|
||||
current_peer->address.size);
|
||||
next_iv(current_peer);
|
||||
|
||||
if (bytes_written < 0)
|
||||
{
|
||||
current_peer->send_errors++;
|
||||
retval++;
|
||||
continue;
|
||||
}
|
||||
if (bytes_written != NCRYPT_PACKET_OVERHEAD + encrypted_used)
|
||||
{
|
||||
current_peer->partial_writes++;
|
||||
retval++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return (int)bytes_written;
|
||||
return retval;
|
||||
}
|
||||
|
||||
int ncrypt_decrypt_recv(struct ncrypt * const nc, int fd, struct ncrypt_buffer * const buf)
|
||||
int ncrypt_dgram_recv(struct ncrypt * const nc, int fd, char * const plaintext, size_t plaintext_size)
|
||||
{
|
||||
ssize_t bytes_read = read(fd, buf->encrypted.raw, sizeof(buf->encrypted.raw));
|
||||
if (plaintext_size > NCRYPT_BUFFER_SIZE)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct nDPIsrvd_address remote = {.size = sizeof(remote.raw)};
|
||||
union packet encrypted;
|
||||
ssize_t bytes_read = recvfrom(fd, encrypted.raw, sizeof(encrypted.raw), 0, &remote.raw, &remote.size);
|
||||
|
||||
if (bytes_read < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (bytes_read < NCRYPT_AES_IVLEN + NCRYPT_TAG_SIZE + 1)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (memcmp(nc->iv, buf->encrypted.iv, NCRYPT_AES_IVLEN) != 0)
|
||||
{
|
||||
nc->iv_mismatches++;
|
||||
}
|
||||
memcpy(nc->iv, buf->encrypted.iv, NCRYPT_AES_IVLEN);
|
||||
int decrypted_used = decrypt(nc,
|
||||
buf->encrypted.data,
|
||||
bytes_read - NCRYPT_AES_IVLEN - NCRYPT_TAG_SIZE,
|
||||
buf->encrypted.tag,
|
||||
buf->plaintext.data);
|
||||
next_iv(nc);
|
||||
|
||||
if (decrypted_used < 0)
|
||||
if (bytes_read < NCRYPT_PACKET_MIN_SIZE)
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
if (plaintext_size < (size_t)bytes_read - NCRYPT_PACKET_OVERHEAD)
|
||||
{
|
||||
return -4;
|
||||
}
|
||||
|
||||
buf->data_used = decrypted_used;
|
||||
struct peer * peer = ncrypt_get_peer(nc, &remote);
|
||||
if (peer == NULL)
|
||||
{
|
||||
if (ncrypt_add_peer(nc, &remote) != 0)
|
||||
{
|
||||
return -5;
|
||||
}
|
||||
peer = ncrypt_get_peer(nc, &remote);
|
||||
ncrypt_init_decrypt(nc, &peer->aes);
|
||||
}
|
||||
|
||||
return (int)bytes_read;
|
||||
if (memcmp(peer->iv, encrypted.iv, NCRYPT_AES_IVLEN) != 0)
|
||||
{
|
||||
peer->iv_mismatches++;
|
||||
memcpy(peer->iv, encrypted.iv, NCRYPT_AES_IVLEN);
|
||||
}
|
||||
int decrypted_used =
|
||||
decrypt(&peer->aes, encrypted.data, bytes_read - NCRYPT_PACKET_OVERHEAD, peer->iv, encrypted.tag, plaintext);
|
||||
next_iv(peer);
|
||||
|
||||
if (decrypted_used < 0)
|
||||
{
|
||||
return -6;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
102
ncrypt.h
102
ncrypt.h
@@ -4,63 +4,43 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "nDPIsrvd.h"
|
||||
|
||||
#define NCRYPT_X25519_KEYLEN 32
|
||||
#define NCRYPT_AES_IVLEN 12
|
||||
#define NCRYPT_TAG_SIZE 16
|
||||
#define NCRYPT_BUFFER_SIZE NETWORK_BUFFER_MAX_SIZE
|
||||
#define NCRYPT_PACKET_BUFFER_SIZE NCRYPT_AES_IVLEN + NCRYPT_TAG_SIZE + NCRYPT_BUFFER_SIZE
|
||||
#define NCRYPT_PACKET_OVERHEAD (NCRYPT_AES_IVLEN + NCRYPT_TAG_SIZE)
|
||||
#define NCRYPT_PACKET_BUFFER_SIZE (NCRYPT_PACKET_OVERHEAD + NCRYPT_BUFFER_SIZE)
|
||||
#define NCRYPT_PACKET_MIN_SIZE (NCRYPT_PACKET_OVERHEAD + NETWORK_BUFFER_LENGTH_DIGITS + 1)
|
||||
|
||||
struct aes
|
||||
{
|
||||
void * ctx;
|
||||
};
|
||||
|
||||
struct peer
|
||||
{
|
||||
nDPIsrvd_hashkey hash_key;
|
||||
struct nDPIsrvd_address address;
|
||||
unsigned char iv[NCRYPT_AES_IVLEN];
|
||||
size_t crypto_errors;
|
||||
size_t iv_mismatches;
|
||||
size_t send_errors;
|
||||
size_t recv_errors;
|
||||
size_t partial_writes;
|
||||
struct aes aes;
|
||||
UT_hash_handle hh;
|
||||
};
|
||||
|
||||
struct ncrypt
|
||||
{
|
||||
void * libctx;
|
||||
void * aesctx;
|
||||
unsigned char * shared_secret;
|
||||
const char * propq;
|
||||
struct
|
||||
{
|
||||
void * priv_key;
|
||||
unsigned char pub_key[NCRYPT_X25519_KEYLEN];
|
||||
} local;
|
||||
struct
|
||||
{
|
||||
void * pub_key;
|
||||
} remote;
|
||||
unsigned char iv[NCRYPT_AES_IVLEN];
|
||||
size_t iv_mismatches;
|
||||
size_t partial_writes;
|
||||
unsigned char shared_secret[NCRYPT_X25519_KEYLEN];
|
||||
struct peer * peers;
|
||||
};
|
||||
|
||||
struct ncrypt_buffer
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned char data[NCRYPT_BUFFER_SIZE];
|
||||
} plaintext;
|
||||
|
||||
struct
|
||||
{
|
||||
union
|
||||
{
|
||||
unsigned char raw[NCRYPT_PACKET_BUFFER_SIZE];
|
||||
struct
|
||||
{
|
||||
unsigned char iv[NCRYPT_AES_IVLEN];
|
||||
unsigned char tag[NCRYPT_TAG_SIZE];
|
||||
unsigned char data[NCRYPT_BUFFER_SIZE];
|
||||
} __attribute__((__packed__));
|
||||
};
|
||||
} encrypted;
|
||||
|
||||
size_t data_used; // size of plaintext and encrypted is equal for AES-GCM
|
||||
size_t write_offset; // partial write; offset to next bytes of data
|
||||
};
|
||||
|
||||
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
|
||||
_Static_assert(sizeof(((struct ncrypt_buffer *)0)->encrypted) == sizeof(((struct ncrypt_buffer *)0)->encrypted.raw),
|
||||
"Raw buffer and iv/tag/data sizes differ");
|
||||
#endif
|
||||
|
||||
int ncrypt_keygen(unsigned char priv_key[NCRYPT_X25519_KEYLEN], unsigned char pub_key[NCRYPT_X25519_KEYLEN]);
|
||||
|
||||
int ncrypt_load_privkey(char const * const private_key_file, unsigned char priv_key[NCRYPT_X25519_KEYLEN]);
|
||||
@@ -71,26 +51,38 @@ int ncrypt_init(struct ncrypt * const nc,
|
||||
unsigned char local_priv_key[NCRYPT_X25519_KEYLEN],
|
||||
unsigned char remote_pub_key[NCRYPT_X25519_KEYLEN]);
|
||||
|
||||
int ncrypt_init_encrypt(struct ncrypt * const nc);
|
||||
int ncrypt_init_encrypt(struct ncrypt * const nc, struct aes * const aes);
|
||||
|
||||
int ncrypt_init_decrypt(struct ncrypt * const nc);
|
||||
int ncrypt_init_encrypt2(struct ncrypt * const nc, struct nDPIsrvd_address * const peer_address);
|
||||
|
||||
int ncrypt_init_decrypt(struct ncrypt * const nc, struct aes * const aes);
|
||||
|
||||
int ncrypt_init_decrypt2(struct ncrypt * const nc, struct nDPIsrvd_address * const peer_address);
|
||||
|
||||
void ncrypt_free_aes(struct aes * const aes);
|
||||
|
||||
void ncrypt_free(struct ncrypt * const nc);
|
||||
|
||||
int ncrypt_encrypt(struct ncrypt * const nc,
|
||||
unsigned char const * const plaintext,
|
||||
size_t used,
|
||||
int ncrypt_add_peer(struct ncrypt * const nc, struct nDPIsrvd_address const * const peer_address);
|
||||
|
||||
struct peer * ncrypt_get_peer(struct ncrypt * const nc, struct nDPIsrvd_address const * const peer_address);
|
||||
|
||||
int ncrypt_encrypt(struct aes * const aes,
|
||||
char const * const plaintext,
|
||||
size_t plaintext_size,
|
||||
unsigned char const iv[NCRYPT_AES_IVLEN],
|
||||
unsigned char encrypted[NCRYPT_BUFFER_SIZE],
|
||||
unsigned char tag[NCRYPT_TAG_SIZE]);
|
||||
|
||||
int ncrypt_decrypt(struct ncrypt * const nc,
|
||||
int ncrypt_decrypt(struct aes * const aes,
|
||||
unsigned char const * const encrypted,
|
||||
size_t used,
|
||||
size_t encrypted_size,
|
||||
unsigned char const iv[NCRYPT_AES_IVLEN],
|
||||
unsigned char tag[NCRYPT_TAG_SIZE],
|
||||
unsigned char plaintext[NCRYPT_BUFFER_SIZE]);
|
||||
char plaintext[NCRYPT_BUFFER_SIZE]);
|
||||
|
||||
int ncrypt_encrypt_send(struct ncrypt * const nc, int fd, struct ncrypt_buffer * const buf);
|
||||
int ncrypt_dgram_send(struct ncrypt * const nc, int fd, char const * const plaintext, size_t plaintext_size);
|
||||
|
||||
int ncrypt_decrypt_recv(struct ncrypt * const nc, int fd, struct ncrypt_buffer * const buf);
|
||||
int ncrypt_dgram_recv(struct ncrypt * const nc, int fd, char * const plaintext, size_t plaintext_size);
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user