Simple AES chat program
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

284 lines
6.1 KiB

#include "comm.h"
#include "randsource.h"
#include "aes.h"
#include <gmp.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netdb.h>
#include <string.h>
#include <errno.h>
#define RAND_SIZE 512
void sess_init(struct session *sess)
{
mpz_t seed;
mpz_init(seed);
char *randbuff = malloc(RAND_SIZE);
gmp_randinit_default(sess->rs);
fill_random(randbuff, RAND_SIZE);
mpz_import(seed, RAND_SIZE, 1, 1, 0, 0, randbuff);
gmp_randseed(sess->rs, seed);
free(randbuff);
mpz_init(sess->eg.m);
mpz_init(sess->eg.g);
mpz_init(sess->eg.p);
mpz_init(sess->eg.x);
mpz_clear(seed);
}
void sess_destroy(struct session *sess)
{
mpz_clear(sess->eg.m);
mpz_clear(sess->eg.g);
mpz_clear(sess->eg.p);
mpz_clear(sess->eg.x);
gmp_randclear(sess->rs);
}
int do_resolve(char *address, char *portstr, struct sock_params *params)
{
if (strspn(address, "unix:") == 5)
{
address += 5;
int sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock == -1)
return errno;
struct sockaddr_un *addr = malloc(sizeof(struct sockaddr_un));;
addr->sun_family = AF_UNIX; // Polymorphism in C is pretty cool.
strncpy(addr->sun_path, address, sizeof(addr->sun_path) - 1);
addr->sun_path[sizeof(addr->sun_path) - 1] = 0;
params->sock = sock;
params->addr = (struct sockaddr*) addr;
params->addrlen = sizeof(struct sockaddr_un);
params->freeme = NULL;
} else
{
struct addrinfo hints =
{
.ai_flags = 0,
.ai_family = AF_UNSPEC,
.ai_socktype = SOCK_STREAM,
.ai_protocol = 0,
};
struct addrinfo *ai;
unsigned short port = 7140;
int err;
if (portstr == NULL)
{
if ((err = getaddrinfo(address, NULL, &hints, &ai)))
{
return err;
}
((struct sockaddr_in*) ai->ai_addr)->sin_port = htons(port);
} else if (1 == sscanf(portstr, "%hu", &port))
{
if ((err = getaddrinfo(address, NULL, &hints, &ai)))
{
return err;
}
((struct sockaddr_in*) ai->ai_addr)->sin_port = htons(port);
} else
{
if ((err = getaddrinfo(address, portstr, &hints, &ai)))
{
return err;
}
}
int sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if (sock == -1)
return errno;
params->sock = sock;
params->addr = ai->ai_addr;
params->addrlen = ai->ai_addrlen;
params->freeme = ai;
}
return 0;
}
void do_unresolve(struct sock_params params)
{
close(params.sock);
if (params.freeme == NULL)
free(params.addr);
freeaddrinfo(params.freeme);
}
int send_num(mpz_t n, struct session *sess)
{
size_t nbytes;
void *buf = mpz_export(NULL, &nbytes, 1, 1, 1, 0, n);
if (nbytes >= (1 << 16))
{
free(buf);
return -1;
}
uint16_t size = htons((uint16_t) nbytes);
write(sess->params.sock, &size, 2);
write(sess->params.sock, buf, nbytes);
free(buf);
return 0;
}
int recv_num(mpz_t n, struct session *sess)
{
uint16_t size = 0;
read(sess->params.sock, &size, 2);
size_t nbytes = ntohs(size);
void *buf = malloc(nbytes);
read(sess->params.sock, buf, nbytes);
mpz_import(n, nbytes, 1, 1, 1, 0, buf);
free(buf);
return 0;
}
int send_data(char data[16], struct session *sess)
{
write(sess->params.sock, data, 16);
return 0;
}
int recv_data(char data[16], struct session *sess)
{
if (!read(sess->params.sock, data, 16))
return 1;
return 0;
}
void initial_aes_handshake(struct session *sess)
{
fill_random(sess->last_sent_enc, 16);
send_data(sess->last_sent_enc, sess);
AESRound_data(sess->last_sent_enc, sess->key);
recv_data(sess->last_recv_enc, sess);
AESRound_data(sess->last_recv_enc, sess->key);
}
int do_connect(struct session *sess)
{
int en = connect(sess->params.sock, sess->params.addr, sess->params.addrlen);
if (en != 0)
return en;
uint32_t rshort_key[8], short_key[8] = {0};
fill_random(rshort_key, 32);
recv_num(sess->eg.m, sess);
recv_num(sess->eg.g, sess);
recv_num(sess->eg.p, sess);
mpz_t a, k, h;
mpz_init(a);
mpz_init(k);
mpz_init(h);
mpz_urandomm(a, sess->rs, sess->eg.m);
mpz_import(k, 8, 1, 4, 1, 0, rshort_key);
mpz_mod(k, k, sess->eg.m);
size_t nbytes;
void *buf = mpz_export(NULL, &nbytes, -1, 4, 1, 0, k);
memcpy(short_key, buf, 32);
free(buf);
expandKey(short_key, sess->key);
mpz_powm(h, sess->eg.g, a, sess->eg.m);
mpz_powm(a, sess->eg.p, a, sess->eg.m);
mpz_mul(a, k, a);
mpz_mod(a, a, sess->eg.m);
send_num(h, sess);
send_num(a, sess);
mpz_clear(a);
mpz_clear(k);
mpz_clear(h);
initial_aes_handshake(sess);
return 0;
}
int do_receive(struct session *sess)
{
int en = bind(sess->params.sock, sess->params.addr, sess->params.addrlen);
if (en != 0)
return en;
en = listen(sess->params.sock, 1);
if (en != 0)
return en;
en = accept(sess->params.sock, NULL, NULL);
if (en == -1)
return errno;
close(sess->params.sock);
sess->params.sock = en;
struct linger linger = {0, 0};
setsockopt(sess->params.sock, SOL_SOCKET, SO_LINGER, &linger, sizeof(struct linger));
uint32_t short_key[8] = {0};
send_num(sess->eg.m, sess);
send_num(sess->eg.g, sess);
send_num(sess->eg.p, sess);
mpz_t h, f, a;
mpz_init(h);
mpz_init(f);
mpz_init(a);
recv_num(h, sess);
recv_num(a, sess);
mpz_neg(f, sess->eg.x);
mpz_powm(f, h, f, sess->eg.m);
mpz_mul(a, a, f);
mpz_mod(a, a, sess->eg.m);
size_t nbytes;
void *buf = mpz_export(NULL, &nbytes, -1, 4, 1, 0, a);
memcpy(short_key, buf, 32);
free(buf);
expandKey(short_key, sess->key);
mpz_clear(h);
mpz_clear(f);
mpz_clear(a);
initial_aes_handshake(sess);
return 0;
}
void send_encrypted_byte(struct session *sess, char byte)
{
fill_random(sess->last_sent_enc, 15);
sess->last_sent_enc[15] ^= byte;
send_data(sess->last_sent_enc, sess);
AESRound_data(sess->last_sent_enc, sess->key);
}
int recv_encrypted_byte(struct session *sess)
{
char buffer[16];
memcpy(buffer, sess->last_recv_enc, 16);
if (recv_data(sess->last_recv_enc, sess))
return EOF;
buffer[15] ^= sess->last_recv_enc[15];
AESRound_data(sess->last_recv_enc, sess->key);
return buffer[15];
}