Initial commit
This commit is contained in:
commit
297f55bc60
9 changed files with 801 additions and 0 deletions
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
zsm
|
||||||
|
zsmc
|
||||||
|
*.o
|
||||||
|
*.tar.gz
|
52
Makefile
Normal file
52
Makefile
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
.POSIX:
|
||||||
|
.SUFFIXES:
|
||||||
|
|
||||||
|
CC = cc
|
||||||
|
VERSION = 1.0
|
||||||
|
SERVER = zsm
|
||||||
|
CLIENT = zsmc
|
||||||
|
MANPAGE = $(TARGET).1
|
||||||
|
PREFIX ?= /usr/local
|
||||||
|
BINDIR = $(PREFIX)/bin
|
||||||
|
MANDIR = $(PREFIX)/share/man/man1
|
||||||
|
|
||||||
|
# Flags
|
||||||
|
LDFLAGS = $(shell pkg-config --libs libsodium libnotify ncurses)
|
||||||
|
CFLAGS = -O3 -mtune=native -march=native -pipe -g -std=c99 -Wno-pointer-sign -Wpedantic -Wall -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600 $(shell pkg-config --cflags libsodium libnotify ncurses) -lpthread
|
||||||
|
|
||||||
|
SERVERSRC = src/server/*.c
|
||||||
|
CLIENTSRC = src/client/*.c
|
||||||
|
LIBSRC = lib/*.c
|
||||||
|
INCLUDE = -Iinclude/
|
||||||
|
|
||||||
|
$(SERVER): $(SERVERSRC) $(LIBSRC)
|
||||||
|
$(CC) $(SERVERSRC) $(LIBSRC) $(INCLUDE) -o $@ $(CFLAGS) $(LDFLAGS)
|
||||||
|
|
||||||
|
$(CLIENT): $(CLIENTSRC) $(LIBSRC)
|
||||||
|
$(CC) $(CLIENTSRC) $(LIBSRC) $(INCLUDE) -o $@ $(CFLAGS) $(LDFLAGS)
|
||||||
|
|
||||||
|
dist:
|
||||||
|
mkdir -p $(TARGET)-$(VERSION)
|
||||||
|
cp -R README.md $(MANPAGE) $(TARGET) $(TARGET)-$(VERSION)
|
||||||
|
tar -cf $(TARGET)-$(VERSION).tar $(TARGET)-$(VERSION)
|
||||||
|
gzip $(TARGET)-$(VERSION).tar
|
||||||
|
rm -rf $(TARGET)-$(VERSION)
|
||||||
|
|
||||||
|
install: $(TARGET)
|
||||||
|
mkdir -p $(DESTDIR)$(BINDIR)
|
||||||
|
mkdir -p $(DESTDIR)$(MANDIR)
|
||||||
|
cp -p $(TARGET) $(DESTDIR)$(BINDIR)/$(TARGET)
|
||||||
|
chmod 755 $(DESTDIR)$(BINDIR)/$(TARGET)
|
||||||
|
cp -p $(MANPAGE) $(DESTDIR)$(MANDIR)/$(MANPAGE)
|
||||||
|
chmod 644 $(DESTDIR)$(MANDIR)/$(MANPAGE)
|
||||||
|
|
||||||
|
uninstall:
|
||||||
|
$(RM) $(DESTDIR)$(BINDIR)/$(TARGET)
|
||||||
|
$(RM) $(DESTDIR)$(MANDIR)/$(MANPAGE)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) $(TARGET)
|
||||||
|
|
||||||
|
all: $(TARGET)
|
||||||
|
|
||||||
|
.PHONY: all dist install uninstall clean
|
22
README.md
Normal file
22
README.md
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
# zsm
|
||||||
|
|
||||||
|
Zen Secure Messaging(zsm) is a secure messaging protocol specifically for Linux(Unix-based) systems.
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
- sqlite
|
||||||
|
- libsodium
|
||||||
|
- libnotify
|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
> You will need to run these with elevated privilages.
|
||||||
|
> You will need `*-dev` packages to build both server and client.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git clone https://github.com/night0721/zsm
|
||||||
|
make
|
||||||
|
make install
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
This project is licensed under the GNU Public License v3.0. See [LICENSE](https://github.com/night0721/zsm/blob/master/LICENSE) for more information.
|
8
include/notification.h
Normal file
8
include/notification.h
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#ifndef NOTIFICATION_H
|
||||||
|
#define NOTIFICATION_H
|
||||||
|
|
||||||
|
#include <libnotify/notify.h>
|
||||||
|
|
||||||
|
void send_notification(const char *content);
|
||||||
|
|
||||||
|
#endif
|
69
include/packet.h
Normal file
69
include/packet.h
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
#ifndef PACKET_H
|
||||||
|
#define PACKET_H
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <sodium.h>
|
||||||
|
|
||||||
|
#define DEBUG 1
|
||||||
|
#define DOMAIN "127.0.0.1"
|
||||||
|
#define PORT 20247
|
||||||
|
#define MAX_CONNECTION 5
|
||||||
|
#define MAX_MESSAGE_LENGTH 8192
|
||||||
|
#define ERROR_LENGTH 26
|
||||||
|
|
||||||
|
#define ZSM_TYP_KEY 0x1
|
||||||
|
#define ZSM_TYP_SEND_MESSAGE 0x2
|
||||||
|
#define ZSM_TYP_UPDATE_MESSAGE 0x3
|
||||||
|
#define ZSM_TYP_DELETE_MESSAGE 0x4
|
||||||
|
#define ZSM_TYP_PRESENCE 0x5
|
||||||
|
#define ZSM_TYP_TYPING 0x6
|
||||||
|
#define ZSM_TYP_ERROR 0x7 /* Error message */
|
||||||
|
#define ZSM_TYP_B 0x8
|
||||||
|
|
||||||
|
#define ZSM_STA_SUCCESS 0x1
|
||||||
|
#define ZSM_STA_INVALID_TYPE 0x2
|
||||||
|
#define ZSM_STA_INVALID_LENGTH 0x3
|
||||||
|
#define ZSM_STA_TOO_LONG 0x4
|
||||||
|
#define ZSM_STA_READING_SOCKET 0x5
|
||||||
|
#define ZSM_STA_WRITING_SOCKET 0x6
|
||||||
|
#define ZSM_STA_UNKNOWN_USER 0x7
|
||||||
|
#define ZSM_STA_MEMORY_ALLOCATION 0x8
|
||||||
|
#define ZSM_STA_WRONG_KEY_LENGTH 0x9
|
||||||
|
|
||||||
|
#define PUBLIC_KEY_SIZE crypto_kx_PUBLICKEYBYTES
|
||||||
|
#define PRIVATE_KEY_SIZE crypto_kx_SECRETKEYBYTES
|
||||||
|
#define SHARED_KEY_SIZE crypto_kx_SESSIONKEYBYTES
|
||||||
|
#define NONCE_SIZE crypto_aead_xchacha20poly1305_ietf_NPUBBYTES
|
||||||
|
#define ADDITIONAL_SIZE crypto_aead_xchacha20poly1305_ietf_ABYTES
|
||||||
|
|
||||||
|
typedef struct message {
|
||||||
|
uint8_t option;
|
||||||
|
uint8_t type;
|
||||||
|
unsigned long long length;
|
||||||
|
unsigned char *data;
|
||||||
|
} message;
|
||||||
|
|
||||||
|
/* Utilities functions */
|
||||||
|
void error(int fatal, const char *fmt, ...);
|
||||||
|
void *memalloc(size_t size);
|
||||||
|
void *estrdup(void *str);
|
||||||
|
unsigned char *get_public_key(int sockfd);
|
||||||
|
int send_public_key(int sockfd, unsigned char *pk);
|
||||||
|
void print_packet(message *msg);
|
||||||
|
int recv_packet(message *msg, int fd);
|
||||||
|
message *create_error_packet(int code);
|
||||||
|
message *create_packet(uint8_t option, uint8_t type, uint32_t length, char *data);
|
||||||
|
int send_packet(message *msg, int fd);
|
||||||
|
void free_packet(message *msg);
|
||||||
|
|
||||||
|
#endif
|
8
lib/notification.c
Normal file
8
lib/notification.c
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#include "notification.h"
|
||||||
|
|
||||||
|
void send_notification(const char *content)
|
||||||
|
{
|
||||||
|
NotifyNotification *noti = notify_notification_new("Client", content, "dialog-information");
|
||||||
|
notify_notification_show(noti, NULL);
|
||||||
|
g_object_unref(G_OBJECT(noti));
|
||||||
|
}
|
273
lib/packet.c
Normal file
273
lib/packet.c
Normal file
|
@ -0,0 +1,273 @@
|
||||||
|
#include "packet.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* msg is the error message to print to stderr
|
||||||
|
* will include error message from function if errno isn't 0
|
||||||
|
* end program is fatal is 1
|
||||||
|
*/
|
||||||
|
void error(int fatal, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
|
||||||
|
/* to preserve errno */
|
||||||
|
int errsv = errno;
|
||||||
|
|
||||||
|
/* Determine the length of the formatted error message */
|
||||||
|
va_list args_copy;
|
||||||
|
va_copy(args_copy, args);
|
||||||
|
size_t error_len = vsnprintf(NULL, 0, fmt, args_copy);
|
||||||
|
va_end(args_copy);
|
||||||
|
|
||||||
|
/* 7 for [zsm], space and null */
|
||||||
|
char errorstr[error_len + 1];
|
||||||
|
vsnprintf(errorstr, error_len + 1, fmt, args);
|
||||||
|
fprintf(stderr, "[zsm] ");
|
||||||
|
|
||||||
|
if (errsv != 0) {
|
||||||
|
perror(errorstr);
|
||||||
|
errno = 0;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "%s\n", errorstr);
|
||||||
|
}
|
||||||
|
|
||||||
|
va_end(args);
|
||||||
|
if (fatal) exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *memalloc(size_t size)
|
||||||
|
{
|
||||||
|
void *ptr = malloc(size);
|
||||||
|
if (!ptr) {
|
||||||
|
error(0, "Error allocating memory");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *estrdup(void *str)
|
||||||
|
{
|
||||||
|
void *modstr = strdup(str);
|
||||||
|
if (modstr == NULL) {
|
||||||
|
error(0, "Error allocating memory");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return modstr;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *get_public_key(int sockfd)
|
||||||
|
{
|
||||||
|
message keyex_msg;
|
||||||
|
if (recv_packet(&keyex_msg, sockfd) != ZSM_STA_SUCCESS) {
|
||||||
|
/* We can't do anything if key exchange already failed */
|
||||||
|
close(sockfd);
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
int status = 0;
|
||||||
|
/* Check to see if the content is actually a key */
|
||||||
|
if (keyex_msg.type != ZSM_TYP_KEY) {
|
||||||
|
status = ZSM_STA_INVALID_TYPE;
|
||||||
|
}
|
||||||
|
if (keyex_msg.length != PUBLIC_KEY_SIZE) {
|
||||||
|
status = ZSM_STA_WRONG_KEY_LENGTH;
|
||||||
|
}
|
||||||
|
if (status != 0) {
|
||||||
|
free(keyex_msg.data);
|
||||||
|
message *error_msg = create_error_packet(status);
|
||||||
|
send_packet(error_msg, sockfd);
|
||||||
|
free_packet(error_msg);
|
||||||
|
close(sockfd);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Obtain public key from packet */
|
||||||
|
uint8_t *pk = memalloc(PUBLIC_KEY_SIZE * sizeof(char));
|
||||||
|
memcpy(pk, keyex_msg.data, PUBLIC_KEY_SIZE);
|
||||||
|
if (pk == NULL) {
|
||||||
|
free(keyex_msg.data);
|
||||||
|
/* Fatal, we couldn't complete key exchange */
|
||||||
|
close(sockfd);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
free(keyex_msg.data);
|
||||||
|
return pk;
|
||||||
|
}
|
||||||
|
|
||||||
|
int send_public_key(int sockfd, uint8_t *pk)
|
||||||
|
{
|
||||||
|
/* send_packet requires heap allocated buffer */
|
||||||
|
uint8_t *pk_dup = memalloc(PUBLIC_KEY_SIZE * sizeof(char));
|
||||||
|
memcpy(pk_dup, pk, PUBLIC_KEY_SIZE);
|
||||||
|
if (pk_dup == NULL) {
|
||||||
|
close(sockfd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sending our public key to client */
|
||||||
|
/* option???? */
|
||||||
|
message *keyex = create_packet(1, ZSM_TYP_KEY, PUBLIC_KEY_SIZE, pk_dup);
|
||||||
|
send_packet(keyex, sockfd);
|
||||||
|
free_packet(keyex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_packet(message *msg)
|
||||||
|
{
|
||||||
|
printf("Option: %d\n", msg->option);
|
||||||
|
printf("Type: %d\n", msg->type);
|
||||||
|
printf("Length: %lld\n", msg->length);
|
||||||
|
printf("Data: %s\n\n", msg->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Requires manually free message data
|
||||||
|
*/
|
||||||
|
int recv_packet(message *msg, int fd)
|
||||||
|
{
|
||||||
|
int status = ZSM_STA_SUCCESS;
|
||||||
|
|
||||||
|
/* Read the message components */
|
||||||
|
if (recv(fd, &msg->option, sizeof(msg->option), 0) < 0 ||
|
||||||
|
recv(fd, &msg->type, sizeof(msg->type), 0) < 0 ||
|
||||||
|
recv(fd, &msg->length, sizeof(msg->length), 0) < 0) {
|
||||||
|
status = ZSM_STA_READING_SOCKET;
|
||||||
|
error(0, "Error reading from socket");
|
||||||
|
}
|
||||||
|
#if DEBUG == 1
|
||||||
|
printf("==========PACKET RECEIVED==========\n");
|
||||||
|
#endif
|
||||||
|
#if DEBUG == 1
|
||||||
|
printf("Option: %d\n", msg->option);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (msg->type > 0xFF || msg->type < 0x0) {
|
||||||
|
status = ZSM_STA_INVALID_TYPE;
|
||||||
|
error(0, "Invalid message type");
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
#if DEBUG == 1
|
||||||
|
printf("Type: %d\n", msg->type);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Convert message length from network byte order to host byte order */
|
||||||
|
if (msg->length > MAX_MESSAGE_LENGTH) {
|
||||||
|
status = ZSM_STA_TOO_LONG;
|
||||||
|
error(0, "Message too long: %lld", msg->length);
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
#if DEBUG == 1
|
||||||
|
printf("Length: %lld\n", msg->length);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Allocate memory for message data
|
||||||
|
msg->data = memalloc((msg->length + 1) * sizeof(char));
|
||||||
|
if (msg->data == NULL) {
|
||||||
|
status = ZSM_STA_MEMORY_ALLOCATION;
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read message data from the socket */
|
||||||
|
size_t bytes_read = 0;
|
||||||
|
if ((bytes_read = recv(fd, msg->data, msg->length, 0)) < 0) {
|
||||||
|
status = ZSM_STA_READING_SOCKET;
|
||||||
|
error(0, "Error reading from socket");
|
||||||
|
free(msg->data);
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
if (bytes_read != msg->length) {
|
||||||
|
status = ZSM_STA_INVALID_LENGTH;
|
||||||
|
error(0, "Invalid message length: bytes_read=%ld != msg->length=%lld", bytes_read, msg->length);
|
||||||
|
free(msg->data);
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
msg->data[msg->length] = '\0';
|
||||||
|
|
||||||
|
#if DEBUG == 1
|
||||||
|
printf("Data: %s\n\n", msg->data);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return status;
|
||||||
|
failure:;
|
||||||
|
message *error_msg = create_error_packet(status);
|
||||||
|
if (send_packet(error_msg, fd) != ZSM_STA_SUCCESS) {
|
||||||
|
/* Resend it? */
|
||||||
|
error(0, "Failed to send error packet to peer. Error status => %d", status);
|
||||||
|
}
|
||||||
|
free_packet(error_msg);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
message *create_error_packet(int code)
|
||||||
|
{
|
||||||
|
char *err = memalloc(ERROR_LENGTH * sizeof(char));
|
||||||
|
switch (code) {
|
||||||
|
case ZSM_STA_INVALID_TYPE:
|
||||||
|
strcpy(err, "Invalid message type ");
|
||||||
|
break;
|
||||||
|
case ZSM_STA_INVALID_LENGTH:
|
||||||
|
strcpy(err, "Invalid message length ");
|
||||||
|
break;
|
||||||
|
case ZSM_STA_TOO_LONG:
|
||||||
|
strcpy(err, "Message too long ");
|
||||||
|
break;
|
||||||
|
case ZSM_STA_READING_SOCKET:
|
||||||
|
strcpy(err, "Error reading from socket");
|
||||||
|
break;
|
||||||
|
case ZSM_STA_WRITING_SOCKET:
|
||||||
|
strcpy(err, "Error writing to socket ");
|
||||||
|
break;
|
||||||
|
case ZSM_STA_UNKNOWN_USER:
|
||||||
|
strcpy(err, "Unknwon user ");
|
||||||
|
break;
|
||||||
|
case ZSM_STA_WRONG_KEY_LENGTH:
|
||||||
|
strcpy(err, "Wrong public key length ");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return create_packet(1, ZSM_TYP_ERROR, ERROR_LENGTH, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Requires heap allocated msg data
|
||||||
|
*/
|
||||||
|
message *create_packet(uint8_t option, uint8_t type, uint32_t length, char *data)
|
||||||
|
{
|
||||||
|
message *msg = memalloc(sizeof(message));
|
||||||
|
msg->option = option;
|
||||||
|
msg->type = type;
|
||||||
|
msg->length = length;
|
||||||
|
msg->data = data;
|
||||||
|
return msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Requires heap allocated msg data
|
||||||
|
*/
|
||||||
|
int send_packet(message *msg, int fd)
|
||||||
|
{
|
||||||
|
int status = ZSM_STA_SUCCESS;
|
||||||
|
uint32_t length = msg->length;
|
||||||
|
// Send the message back to the client
|
||||||
|
if (send(fd, &msg->option, sizeof(msg->option), 0) <= 0 ||
|
||||||
|
send(fd, &msg->type, sizeof(msg->type), 0) <= 0 ||
|
||||||
|
send(fd, &msg->length, sizeof(msg->length), 0) <= 0 ||
|
||||||
|
send(fd, msg->data, length, 0) <= 0) {
|
||||||
|
status = ZSM_STA_WRITING_SOCKET;
|
||||||
|
error(0, "Error writing to socket");
|
||||||
|
//free(msg->data);
|
||||||
|
close(fd); // Close the socket and continue accepting connections
|
||||||
|
}
|
||||||
|
#if DEBUG == 1
|
||||||
|
printf("==========PACKET SENT==========\n");
|
||||||
|
print_packet(msg);
|
||||||
|
#endif
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_packet(message *msg)
|
||||||
|
{
|
||||||
|
if (msg->type != 0x10) {
|
||||||
|
/* temp solution, dont use stack allocated msg to send to client */
|
||||||
|
free(msg->data);
|
||||||
|
}
|
||||||
|
free(msg);
|
||||||
|
}
|
147
src/client/client.c
Normal file
147
src/client/client.c
Normal file
|
@ -0,0 +1,147 @@
|
||||||
|
#include "packet.h"
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
uint8_t shared_key[SHARED_KEY_SIZE];
|
||||||
|
int sockfd;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Connect to socket server
|
||||||
|
*/
|
||||||
|
int socket_init()
|
||||||
|
{
|
||||||
|
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (sockfd < 0) {
|
||||||
|
error(1, "Error on opening socket");
|
||||||
|
}
|
||||||
|
|
||||||
|
struct hostent *server = gethostbyname(DOMAIN);
|
||||||
|
if (server == NULL) {
|
||||||
|
error(1, "No such host %s", DOMAIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sockaddr_in sv_addr;
|
||||||
|
memset(&sv_addr, 0, sizeof(sv_addr));
|
||||||
|
sv_addr.sin_family = AF_INET;
|
||||||
|
sv_addr.sin_port = htons(PORT);
|
||||||
|
memcpy(&sv_addr.sin_addr.s_addr, server->h_addr, server->h_length);
|
||||||
|
|
||||||
|
/* free(server); */
|
||||||
|
if (connect(sockfd, (struct sockaddr *) &sv_addr, sizeof(sv_addr)) < 0) {
|
||||||
|
error(1, "Error on connect");
|
||||||
|
close(sockfd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
printf("Connected to server at %s\n", DOMAIN);
|
||||||
|
return sockfd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Performs key exchange with server
|
||||||
|
*/
|
||||||
|
int key_exchange(int sockfd)
|
||||||
|
{
|
||||||
|
/* Generate the client's key pair */
|
||||||
|
uint8_t cl_pk[PUBLIC_KEY_SIZE], cl_sk[PRIVATE_KEY_SIZE];
|
||||||
|
crypto_kx_keypair(cl_pk, cl_sk);
|
||||||
|
|
||||||
|
/* Send our public key */
|
||||||
|
if (send_public_key(sockfd, cl_pk) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get public key from server */
|
||||||
|
uint8_t *pk;
|
||||||
|
if ((pk = get_public_key(sockfd)) == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compute a shared key using the server's public key and our secret key */
|
||||||
|
if (crypto_kx_client_session_keys(NULL, shared_key, cl_pk, cl_sk, pk) != 0) {
|
||||||
|
error(1, "Server public key is not acceptable");
|
||||||
|
free(pk);
|
||||||
|
close(sockfd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
free(pk);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *sender()
|
||||||
|
{
|
||||||
|
while (1) {
|
||||||
|
printf("Enter message to send to server: ");
|
||||||
|
fflush(stdout);
|
||||||
|
char line[1024];
|
||||||
|
line[0] = '\0';
|
||||||
|
size_t length = strlen(line);
|
||||||
|
while (length <= 1) {
|
||||||
|
fgets(line, sizeof(line), stdin);
|
||||||
|
length = strlen(line);
|
||||||
|
}
|
||||||
|
length -= 1;
|
||||||
|
line[length] = '\0';
|
||||||
|
|
||||||
|
uint8_t nonce[NONCE_SIZE];
|
||||||
|
uint8_t encrypted[length + ADDITIONAL_SIZE];
|
||||||
|
unsigned long long encrypted_len;
|
||||||
|
|
||||||
|
randombytes_buf(nonce, sizeof(nonce));
|
||||||
|
crypto_aead_xchacha20poly1305_ietf_encrypt(encrypted, &encrypted_len,
|
||||||
|
line, length,
|
||||||
|
NULL, 0, NULL, nonce, shared_key);
|
||||||
|
size_t payload_t = NONCE_SIZE + encrypted_len;
|
||||||
|
uint8_t encryptedwithnonce[payload_t];
|
||||||
|
memcpy(encryptedwithnonce, nonce, NONCE_SIZE);
|
||||||
|
memcpy(encryptedwithnonce + NONCE_SIZE, encrypted, encrypted_len);
|
||||||
|
|
||||||
|
message *msg = create_packet(1, 0x10, payload_t, encryptedwithnonce);
|
||||||
|
if (send_packet(msg, sockfd) != ZSM_STA_SUCCESS) {
|
||||||
|
close(sockfd);
|
||||||
|
}
|
||||||
|
free_packet(msg);
|
||||||
|
}
|
||||||
|
close(sockfd);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void *receiver()
|
||||||
|
{
|
||||||
|
while (1) {
|
||||||
|
message servermsg;
|
||||||
|
if (recv_packet(&servermsg, sockfd) != ZSM_STA_SUCCESS) {
|
||||||
|
close(sockfd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
free(servermsg.data);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
if (sodium_init() < 0) {
|
||||||
|
error(1, "Error initializing libsodium");
|
||||||
|
}
|
||||||
|
sockfd = socket_init();
|
||||||
|
if (key_exchange(sockfd) < 0) {
|
||||||
|
/* Fatal */
|
||||||
|
error(1, "Error performing key exchange with server");
|
||||||
|
}
|
||||||
|
pthread_t recv_worker, send_worker;
|
||||||
|
if (pthread_create(&recv_worker, NULL, sender, NULL) != 0) {
|
||||||
|
fprintf(stderr, "Error creating incoming thread\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pthread_create(&send_worker, NULL, receiver, NULL) != 0) {
|
||||||
|
fprintf(stderr, "Error creating outgoing thread\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Join threads
|
||||||
|
pthread_join(recv_worker, NULL);
|
||||||
|
pthread_join(send_worker, NULL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
218
src/server/server.c
Normal file
218
src/server/server.c
Normal file
|
@ -0,0 +1,218 @@
|
||||||
|
#include "packet.h"
|
||||||
|
#include "notification.h"
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
socklen_t clilen;
|
||||||
|
struct sockaddr_in cli_address;
|
||||||
|
uint8_t shared_key[SHARED_KEY_SIZE];
|
||||||
|
int clientfd;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialise socket server
|
||||||
|
*/
|
||||||
|
int socket_init()
|
||||||
|
{
|
||||||
|
int serverfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (serverfd < 0) {
|
||||||
|
error(1, "Error on opening socket");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reuse addr(for debug) */
|
||||||
|
int optval = 1;
|
||||||
|
if (setsockopt(serverfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0) {
|
||||||
|
|
||||||
|
error(1, "Error at setting SO_REUSEADDR");
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sockaddr_in sv_addr;
|
||||||
|
memset(&sv_addr, 0, sizeof(sv_addr));
|
||||||
|
sv_addr.sin_family = AF_INET;
|
||||||
|
sv_addr.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
sv_addr.sin_port = htons(PORT);
|
||||||
|
|
||||||
|
if (bind(serverfd, (struct sockaddr *) &sv_addr, sizeof(sv_addr)) < 0) {
|
||||||
|
error(1, "Error on bind");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listen(serverfd, MAX_CONNECTION) < 0) {
|
||||||
|
error(1, "Error on listen");
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Listening on port %d\n", PORT);
|
||||||
|
clilen = sizeof(cli_address);
|
||||||
|
return serverfd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Performs key exchange with client
|
||||||
|
*/
|
||||||
|
int key_exchange(int clientfd)
|
||||||
|
{
|
||||||
|
/* Generate the server's key pair */
|
||||||
|
uint8_t sv_pk[PUBLIC_KEY_SIZE], sv_sk[PRIVATE_KEY_SIZE];
|
||||||
|
crypto_kx_keypair(sv_pk, sv_sk);
|
||||||
|
|
||||||
|
/* Get public key from client */
|
||||||
|
uint8_t *pk;
|
||||||
|
if ((pk = get_public_key(clientfd)) == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send our public key */
|
||||||
|
if (send_public_key(clientfd, sv_pk) < 0) {
|
||||||
|
free(pk);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Compute a shared key using the client's public key and our secret key. */
|
||||||
|
if (crypto_kx_server_session_keys(NULL, shared_key, sv_pk, sv_sk, pk) != 0) {
|
||||||
|
error(0, "Client public key is not acceptable");
|
||||||
|
free(pk);
|
||||||
|
close(clientfd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(pk);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void signal_handler(int signal)
|
||||||
|
{
|
||||||
|
switch (signal) {
|
||||||
|
case SIGPIPE:
|
||||||
|
error(0, "SIGPIPE received");
|
||||||
|
break;
|
||||||
|
case SIGABRT:
|
||||||
|
case SIGINT:
|
||||||
|
case SIGTERM:
|
||||||
|
notify_uninit();
|
||||||
|
error(1, "Shutdown signal received");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void *receiver()
|
||||||
|
{
|
||||||
|
int serverfd = socket_init();
|
||||||
|
clientfd = accept(serverfd, (struct sockaddr *) &cli_address, &clilen);
|
||||||
|
if (clientfd < 0) {
|
||||||
|
error(0, "Error on accepting client");
|
||||||
|
/* Continue accpeting connections */
|
||||||
|
/* continue; */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key_exchange(clientfd) < 0) {
|
||||||
|
error(0, "Error performing key exchange with client");
|
||||||
|
/* continue; */
|
||||||
|
}
|
||||||
|
while (1) {
|
||||||
|
message msg;
|
||||||
|
memset(&msg, 0, sizeof(msg));
|
||||||
|
if (recv_packet(&msg, clientfd) != ZSM_STA_SUCCESS) {
|
||||||
|
close(clientfd);
|
||||||
|
break;
|
||||||
|
/* continue; */
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t encrypted_len = msg.length - NONCE_SIZE;
|
||||||
|
size_t msg_len = encrypted_len - ADDITIONAL_SIZE;
|
||||||
|
uint8_t nonce[NONCE_SIZE];
|
||||||
|
uint8_t encrypted[encrypted_len];
|
||||||
|
uint8_t decrypted[msg_len + 1];
|
||||||
|
unsigned long long decrypted_len;
|
||||||
|
memcpy(nonce, msg.data, NONCE_SIZE);
|
||||||
|
memcpy(encrypted, msg.data + NONCE_SIZE, encrypted_len);
|
||||||
|
|
||||||
|
free(msg.data);
|
||||||
|
if (crypto_aead_xchacha20poly1305_ietf_decrypt(decrypted, &decrypted_len,
|
||||||
|
NULL,
|
||||||
|
encrypted, encrypted_len,
|
||||||
|
NULL, 0,
|
||||||
|
nonce, shared_key) != 0) {
|
||||||
|
error(0, "Cannot decrypt message");
|
||||||
|
} else {
|
||||||
|
/* Decrypted message */
|
||||||
|
decrypted[msg_len] = '\0';
|
||||||
|
printf("Decrypted: %s\n", decrypted);
|
||||||
|
send_notification(decrypted);
|
||||||
|
msg.data = malloc(14);
|
||||||
|
strcpy(msg.data, "Received data");
|
||||||
|
msg.length = 14;
|
||||||
|
send_packet(&msg, clientfd);
|
||||||
|
free(msg.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(clientfd);
|
||||||
|
close(serverfd);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *sender()
|
||||||
|
{
|
||||||
|
while (1) {
|
||||||
|
printf("Enter message to send to client: ");
|
||||||
|
fflush(stdout);
|
||||||
|
char line[1024];
|
||||||
|
line[0] = '\0';
|
||||||
|
size_t length = strlen(line);
|
||||||
|
while (length <= 1) {
|
||||||
|
fgets(line, sizeof(line), stdin);
|
||||||
|
length = strlen(line);
|
||||||
|
}
|
||||||
|
length -= 1;
|
||||||
|
line[length] = '\0';
|
||||||
|
|
||||||
|
uint8_t nonce[NONCE_SIZE];
|
||||||
|
uint8_t encrypted[length + ADDITIONAL_SIZE];
|
||||||
|
unsigned long long encrypted_len;
|
||||||
|
|
||||||
|
randombytes_buf(nonce, sizeof(nonce));
|
||||||
|
crypto_aead_xchacha20poly1305_ietf_encrypt(encrypted, &encrypted_len,
|
||||||
|
line, length,
|
||||||
|
NULL, 0, NULL, nonce, shared_key);
|
||||||
|
size_t payload_t = NONCE_SIZE + encrypted_len;
|
||||||
|
uint8_t encryptedwithnonce[payload_t];
|
||||||
|
memcpy(encryptedwithnonce, nonce, NONCE_SIZE);
|
||||||
|
memcpy(encryptedwithnonce + NONCE_SIZE, encrypted, encrypted_len);
|
||||||
|
|
||||||
|
message *msg = create_packet(1, 0x10, payload_t, encryptedwithnonce);
|
||||||
|
if (send_packet(msg, clientfd) != ZSM_STA_SUCCESS) {
|
||||||
|
close(clientfd);
|
||||||
|
}
|
||||||
|
free_packet(msg);
|
||||||
|
}
|
||||||
|
close(clientfd);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
if (sodium_init() < 0) {
|
||||||
|
error(1, "Error initializing libsodium");
|
||||||
|
}
|
||||||
|
/* Init libnotify with app name */
|
||||||
|
if (notify_init("zsm") < 0) {
|
||||||
|
error(1, "Error initializing libnotify");
|
||||||
|
}
|
||||||
|
signal(SIGPIPE, signal_handler);
|
||||||
|
signal(SIGABRT, signal_handler);
|
||||||
|
signal(SIGINT, signal_handler);
|
||||||
|
signal(SIGTERM, signal_handler);
|
||||||
|
|
||||||
|
pthread_t recv_worker, send_worker;
|
||||||
|
if (pthread_create(&recv_worker, NULL, sender, NULL) != 0) {
|
||||||
|
fprintf(stderr, "Error creating incoming thread\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pthread_create(&send_worker, NULL, receiver, NULL) != 0) {
|
||||||
|
fprintf(stderr, "Error creating outgoing thread\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Join threads
|
||||||
|
pthread_join(recv_worker, NULL);
|
||||||
|
pthread_join(send_worker, NULL);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in a new issue