sodiumTest

Libsodium examples, client/server system
git clone https://noulin.net/git/sodiumTest.git
Log | Files | Refs | README

commit a22feb11bc364edecc7423058d6cb19773729696
parent 09a864a5bfdd29c6fa5e039dff4d7393cbd058f3
Author: Remy Noulin <loader2x@gmail.com>
Date:   Wed, 12 Jul 2023 08:32:15 +0200

add client/server with preshared keys

README.md            |   6 +++
presharedClient.c    | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++
presharedClientudp.c | 129 +++++++++++++++++++++++++++++++++++++++++++++++++++
presharedServer.c    | 125 +++++++++++++++++++++++++++++++++++++++++++++++++
presharedServerudp.c | 101 ++++++++++++++++++++++++++++++++++++++++
5 files changed, 489 insertions(+)

Diffstat:
MREADME.md | 6++++++
ApresharedClient.c | 128+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ApresharedClientudp.c | 129+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ApresharedServer.c | 125+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ApresharedServerudp.c | 101+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 489 insertions(+), 0 deletions(-)

diff --git a/README.md b/README.md @@ -31,3 +31,9 @@ The server keeps the same session keys and uses a bloom filter to detect when cl ## `client4.c` and `server4.c` `server4.c` has the client public keys and if the client key is valid when it connects, it is authenticated. The clients can request the server public key, if the server public key is already known, it can send the first encrypted message directly. + +## preshared* client and server +The preshared client/server use public encryption like `client.c` and `server.c`. +- there is no key exchange, the keys are preshared +- a timestamp (in udp version) is used to avoid replay attacks +- the nonces are not stored diff --git a/presharedClient.c b/presharedClient.c @@ -0,0 +1,128 @@ +#! /usr/bin/env sheepy + +/* +client sends data to server. Client doesn't get any responses from the server +The keys are preshared, there is no key exchange. + +The client knows: client secret key, client public key and server public key +The server knows: client public key, server secret key and server public key + +Run this to generate the client and server keys: + +./presharedClient.c generate keys + +The messages don't need to be signed because the client uses the client secret and +the server public keys to encrypt. + +Steps in client +- load keys +- connect to server +- send encrypted message + +Steps in server +- start event loop +- get encrypted message + +It uses public key encryption which is slow compare to secret/symetric key encryption +Secret key encryption is between 25 and 50 times faster than public key encryption depending on the CPU. +With secret key encryption, my computer can encode 4GB/s which is enough (I have 1GB/s network). + +The nonces are not verified, each nonce can be used multiple times, so replay attacks would be successful. +*/ + +#include "libsheepyObject.h" + +#include <sys/types.h> +#include <sys/socket.h> +#include <netdb.h> +#include <netinet/in.h> + +#include "sel.h" + +int main(int ac, char **av) { + + setLogMode(LOG_FUNC); + + if (not selInit()) ret 1; + + const char* clientSecretFilename = "presharedClientSecret.bin"; + const char* clientPublicFilename = "presharedClientPublic.bin"; + const char* serverSecretFilename = "presharedServerSecret.bin"; + const char* serverPublicFilename = "presharedServerPublic.bin"; + keyst clientKeys = init0Var; + keyst serverKeys = init0Var; + + if (ac > 2) { + // generate keys + logI("Generate keys"); + newKeysBuf(&clientKeys); + newKeysBuf(&serverKeys); + pError0(writeFile(clientSecretFilename, clientKeys.secretKey, sizeof(clientKeys.secretKey))); + pError0(writeFile(clientPublicFilename, clientKeys.publicKey, sizeof(clientKeys.publicKey))); + pError0(writeFile(serverSecretFilename, serverKeys.secretKey, sizeof(serverKeys.secretKey))); + pError0(writeFile(serverPublicFilename, serverKeys.publicKey, sizeof(serverKeys.publicKey))); + ret 0; + } + + // load keys + pError0(bLReadFile(clientSecretFilename, clientKeys.secretKey, sizeof(clientKeys.secretKey))); + pError0(bLReadFile(clientPublicFilename, clientKeys.publicKey, sizeof(clientKeys.publicKey))); + pError0(bLReadFile(serverPublicFilename, clientKeys.remotePublicKey, sizeof(clientKeys.remotePublicKey))); + + char *msg = "Hello"; + + logI("message: %s\n", msg); + + + // connect to server + int sock; + struct sockaddr_in server; + struct hostent *hp; + int mysock; + char buf[128*1024]; + int rval; + + sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0){ + perror("Failed to create socket"); + } + + server.sin_family = AF_INET; + + hp = gethostbyname(av[1]); + if (hp==0) { + perror("gethostbyname failed"); + close(sock); + exit(1); + } + + memcpy(&server.sin_addr, hp->h_addr, hp->h_length); + server.sin_port = htons(5000); + + if (connect(sock,(struct sockaddr *) &server, sizeof(server))){ + perror("connect failed"); + close(sock); + exit(1); + } + + void snd(void *buf, size_t sz) { + logVarG(sz); + if(send(sock, buf, sz, 0) < 0){ + perror("send failed"); + close(sock); + exit(1); + } + } + + // send encrypted message + //randombytes_buf(clientKeys.nonce, sizeof(clientKeys.nonce)); + int len = selPublicEncrypt(buf, sizeof(buf), msg, strlen(msg), &clientKeys); + + logVarG(len); + + snd(&len, sizeof(len)); + snd(buf, len); + + close(sock); +} +// vim: set expandtab ts=2 sw=2: diff --git a/presharedClientudp.c b/presharedClientudp.c @@ -0,0 +1,129 @@ +#! /usr/bin/env sheepy + +/* +client sends data to server. Client doesn't get any responses from the server +The keys are preshared, there is no key exchange. + +The client knows: client secret key, client public key and server public key +The server knows: client public key, server secret key and server public key + +Run this to generate the client and server keys: + +./presharedClient.c generate keys + +The messages don't need to be signed because the client uses the client secret and +the server public keys to encrypt. + +Steps in client +- load keys +- connect to server +- send encrypted message + +Steps in server +- start event loop +- get encrypted message + +It uses public key encryption which is slow compare to secret/symetric key encryption +Secret key encryption is between 25 and 50 times faster than public key encryption depending on the CPU. +With secret key encryption, my computer can encode 4GB/s which is enough (I have 1GB/s network). + +The nonces are not verified, each nonce can be used multiple times, so replay attacks would be successful. +*/ + +#include "libsheepyObject.h" + +#include <sys/types.h> +#include <sys/socket.h> +#include <netdb.h> +#include <netinet/in.h> + +#include "sel.h" + +int main(int ac, char **av) { + + setLogMode(LOG_FUNC); + + if (not selInit()) ret 1; + + const char* clientSecretFilename = "presharedClientSecret.bin"; + const char* clientPublicFilename = "presharedClientPublic.bin"; + const char* serverSecretFilename = "presharedServerSecret.bin"; + const char* serverPublicFilename = "presharedServerPublic.bin"; + keyst clientKeys = init0Var; + keyst serverKeys = init0Var; + + if (ac > 2) { + // generate keys + logI("Generate keys"); + newKeysBuf(&clientKeys); + newKeysBuf(&serverKeys); + pError0(writeFile(clientSecretFilename, clientKeys.secretKey, sizeof(clientKeys.secretKey))); + pError0(writeFile(clientPublicFilename, clientKeys.publicKey, sizeof(clientKeys.publicKey))); + pError0(writeFile(serverSecretFilename, serverKeys.secretKey, sizeof(serverKeys.secretKey))); + pError0(writeFile(serverPublicFilename, serverKeys.publicKey, sizeof(serverKeys.publicKey))); + ret 0; + } + + // load keys + pError0(bLReadFile(clientSecretFilename, clientKeys.secretKey, sizeof(clientKeys.secretKey))); + pError0(bLReadFile(clientPublicFilename, clientKeys.publicKey, sizeof(clientKeys.publicKey))); + pError0(bLReadFile(serverPublicFilename, clientKeys.remotePublicKey, sizeof(clientKeys.remotePublicKey))); + + char *msg = "Hello"; + + logI("message: %s\n", msg); + + + // connect to server + int sock; + struct sockaddr_in server; + struct hostent *hp; + typ struct PACKED { + u64 time; + char buf[64*1024]; + } payloadt; + typ struct PACKED { + u8 nonce[crypto_box_NONCEBYTES]; + i32 len; + payloadt payload; + } packett; + packett data = init0Var; + int rval; + + sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (sock < 0){ + perror("Failed to create socket"); + } + + server.sin_family = AF_INET; + + hp = gethostbyname(av[1]); + if (hp==0) { + perror("gethostbyname failed"); + close(sock); + exit(1); + } + + memcpy(&server.sin_addr, hp->h_addr, hp->h_length); + server.sin_port = htons(5000); + + // send encrypted message with nonce + randombytes_buf(clientKeys.nonce, sizeof(clientKeys.nonce)); + memcpy(data.nonce, clientKeys.nonce, sizeof(clientKeys.nonce)); + payloadt payload; + // set timestamp in encrypted message to avoid replay attacks + payload.time = getCurrentUnixTime() /*- 2 */; // uncomment to introduce an error + memcpy(payload.buf, msg, strlen(msg)); + data.len = selPublicEncrypt((u8*)&data.payload, sizeof(data.payload), (u8*)&payload, sizeof(payload.time) + strlen(msg), &clientKeys); + + logVarG(data.len); + + if (sendto(sock, &data, data.len + sizeof(data.len) + sizeof(data.nonce), 0, (const struct sockaddr *)&server, sizeof(server)) < 0) { + perror("send failed"); + close(sock); + exit(1); + } + + close(sock); +} +// vim: set expandtab ts=2 sw=2: diff --git a/presharedServer.c b/presharedServer.c @@ -0,0 +1,125 @@ +#! /usr/bin/env sheepy + +#include "libsheepyObject.h" + +#include <sys/socket.h> +#include <netinet/in.h> + +#include "sel.h" + +int main(int ac, char **av){ + + setLogMode(LOG_FUNC); + + if (not selInit()) ret 1; + + // load keys + const char* clientSecretFilename = "presharedClientSecret.bin"; + const char* clientPublicFilename = "presharedClientPublic.bin"; + const char* serverSecretFilename = "presharedServerSecret.bin"; + const char* serverPublicFilename = "presharedServerPublic.bin"; + keyst clientKeys = init0Var; + keyst serverKeys = init0Var; + + if (isPath(serverPublicFilename) and isPath(serverSecretFilename) and isPath(clientPublicFilename)) { + logI("Loading server keys"); + pError0(bLReadFile(serverSecretFilename, serverKeys.secretKey, sizeof(serverKeys.secretKey))); + pError0(bLReadFile(serverPublicFilename, serverKeys.publicKey, sizeof(serverKeys.publicKey))); + pError0(bLReadFile(clientPublicFilename, serverKeys.remotePublicKey, sizeof(serverKeys.remotePublicKey))); + } + else { + logE("Failed to load the server keys. Stop. Run ./presharedClient.c generate keys"); + ret 1; + } + + + // start event loop + int sock; + struct sockaddr_in server; + int mysock; + char buf[128*1024]; + int rval; + + sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0){ + perror("Failed to create socket"); + ret 1; + } + + server.sin_family = AF_INET; + server.sin_addr.s_addr = INADDR_ANY; + server.sin_port = htons(5000); + + if (bind(sock, (struct sockaddr *) &server, sizeof(server))){ + perror("bind failed"); + ret 1; + } + + listen(sock, 5); + + forever { + mysock = accept(sock, (struct sockaddr *)0, 0); + if (mysock == -1) + perror("accept failed"); + else { + + bool snd(void *buf, size_t sz) { + logVarG(sz); + if(send(mysock, buf, sz, 0) < 0){ + perror("send failed"); + close(mysock); + ret no; + } + ret yes; + } + + bool rcv(void *buf, size_t sz) { + memset(buf, 0, sizeof(buf)); + rval = recv(mysock, buf, sizeof(buf), 0); + if (rval < 0) { + perror("reading message"); + ret no; + } + else if (rval == 0) { + logI("Ending connection"); + close(mysock); + ret no; + } + logVarG(rval); + ret yes; + } + + // get encrypted message + int len; + if (!rcv(&len, sizeof(len))) continue; + rval = recv(mysock, buf, len, MSG_WAITALL); + if (rval < 0) { + perror("reading message"); + close(mysock); + continue; + } + else if (rval == 0) { + logI("Ending connection"); + close(mysock); + continue; + } + logVarG(rval); + + u8 decrypted[1000]; + len = selPublicDecrypt(decrypted, sizeof(decrypted), buf, rval, &serverKeys); + + if (!len) { + logE("failed to decrypt"); + close(mysock); + continue; + } + + decrypted[len] = 0; + + logI("decrypted: %s", decrypted); + + close(mysock); + } + } +} +// vim: set expandtab ts=2 sw=2: diff --git a/presharedServerudp.c b/presharedServerudp.c @@ -0,0 +1,101 @@ +#! /usr/bin/env sheepy + +#include "libsheepyObject.h" + +#include <sys/socket.h> +#include <netinet/in.h> + +#include "sel.h" + +int main(int ac, char **av){ + + setLogMode(LOG_FUNC); + + if (not selInit()) ret 1; + + // load keys + const char* clientSecretFilename = "presharedClientSecret.bin"; + const char* clientPublicFilename = "presharedClientPublic.bin"; + const char* serverSecretFilename = "presharedServerSecret.bin"; + const char* serverPublicFilename = "presharedServerPublic.bin"; + keyst clientKeys = init0Var; + keyst serverKeys = init0Var; + + if (isPath(serverPublicFilename) and isPath(serverSecretFilename) and isPath(clientPublicFilename)) { + logI("Loading server keys"); + pError0(bLReadFile(serverSecretFilename, serverKeys.secretKey, sizeof(serverKeys.secretKey))); + pError0(bLReadFile(serverPublicFilename, serverKeys.publicKey, sizeof(serverKeys.publicKey))); + pError0(bLReadFile(clientPublicFilename, serverKeys.remotePublicKey, sizeof(serverKeys.remotePublicKey))); + } + else { + logE("Failed to load the server keys. Stop. Run ./presharedClient.c generate keys"); + ret 1; + } + + + // start event loop + int sock; + struct sockaddr_in server; + typ struct PACKED { + u64 time; + char buf[64*1024]; + } payloadt; + typ struct PACKED { + u8 nonce[crypto_box_NONCEBYTES]; + i32 len; + payloadt payload; + } packett; + packett data = init0Var; + int rval; + + sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (sock < 0){ + perror("Failed to create socket"); + ret 1; + } + + server.sin_family = AF_INET; + server.sin_addr.s_addr = INADDR_ANY; + server.sin_port = htons(5000); + + if (bind(sock, (struct sockaddr *) &server, sizeof(server))){ + perror("bind failed"); + ret 1; + } + + listen(sock, SOMAXCONN); + + struct sockaddr_in addr; + + forever { + socklen_t ln = sizeof(addr); + ssize_t r = recvfrom(sock, &data, sizeof(data), 0, (struct sockaddr *) &addr, &ln); + if (r == -1) + perror("recvfrom failed"); + elif (r != data.len + sizeof(data.len) + sizeof(data.nonce)) { + logE("Wrong size"); + continue; + } + + memcpy(serverKeys.nonce, data.nonce, sizeof(serverKeys.nonce)); + + payloadt decrypted; + int len = selPublicDecrypt((u8*)&decrypted, sizeof(decrypted), (u8*)&data.payload, data.len, &serverKeys); + + if (!len) { + logE("failed to decrypt"); + continue; + } + + u64 now = getCurrentUnixTime(); + if (decrypted.time < now - 1 or decrypted.time > now + 1) { + logW("Dropping packet. Wrong timestamp %"PRIu64" now %"PRIu64" diff %"PRIi64, decrypted.time, now, (i64)now - (i64)decrypted.time); + continue; + } + + decrypted.buf[len - sizeof(decrypted.time)] = 0; + + logI("decrypted: %s", decrypted.buf); + } +} +// vim: set expandtab ts=2 sw=2: