From 83250980eb778fdee4341347eed2d7a62636e8a9 Mon Sep 17 00:00:00 2001 From: 0xdcarns Date: Mon, 14 Feb 2022 14:21:56 -0500 Subject: [PATCH 1/4] initial chunk approach --- mq/util.go | 6 +- netclient/functions/daemon.go | 6 +- netclient/ncutils/encryption.go | 109 ++++++++++++++++++++++++++++ netclient/ncutils/netclientutils.go | 24 ------ 4 files changed, 115 insertions(+), 30 deletions(-) create mode 100644 netclient/ncutils/encryption.go diff --git a/mq/util.go b/mq/util.go index 5a5c2737..83186261 100644 --- a/mq/util.go +++ b/mq/util.go @@ -10,7 +10,7 @@ import ( func decryptMsg(node *models.Node, msg []byte) ([]byte, error) { if len(msg) <= 24 { // make sure message is of appropriate length - return nil, fmt.Errorf("recieved invalid message from broker %s", string(msg)) + return nil, fmt.Errorf("recieved invalid message from broker %v", msg) } trafficKey, trafficErr := logic.RetrievePrivateTrafficKey() // get server private key @@ -26,7 +26,7 @@ func decryptMsg(node *models.Node, msg []byte) ([]byte, error) { return nil, err } - return ncutils.BoxDecrypt(msg, nodePubTKey, serverPrivTKey) + return ncutils.DeChunk(msg, nodePubTKey, serverPrivTKey) } func encryptMsg(node *models.Node, msg []byte) ([]byte, error) { @@ -46,7 +46,7 @@ func encryptMsg(node *models.Node, msg []byte) ([]byte, error) { return nil, err } - return ncutils.BoxEncrypt(msg, nodePubKey, serverPrivKey) + return ncutils.Chunk(msg, nodePubKey, serverPrivKey) } func publish(node *models.Node, dest string, msg []byte) error { diff --git a/netclient/functions/daemon.go b/netclient/functions/daemon.go index dba4e151..27be60fa 100644 --- a/netclient/functions/daemon.go +++ b/netclient/functions/daemon.go @@ -553,7 +553,7 @@ func publish(cfg *config.ClientConfig, dest string, msg []byte) error { client := SetupMQTT(cfg, true) defer client.Disconnect(250) - encrypted, err := ncutils.BoxEncrypt(msg, serverPubKey, trafficPrivKey) + encrypted, err := ncutils.Chunk(msg, serverPubKey, trafficPrivKey) if err != nil { return err } @@ -570,7 +570,7 @@ func parseNetworkFromTopic(topic string) string { func decryptMsg(cfg *config.ClientConfig, msg []byte) ([]byte, error) { if len(msg) <= 24 { // make sure message is of appropriate length - return nil, fmt.Errorf("recieved invalid message from broker %s", string(msg)) + return nil, fmt.Errorf("recieved invalid message from broker %v", msg) } // setup the keys @@ -584,7 +584,7 @@ func decryptMsg(cfg *config.ClientConfig, msg []byte) ([]byte, error) { return nil, err } - return ncutils.BoxDecrypt(msg, serverPubKey, diskKey) + return ncutils.DeChunk(msg, serverPubKey, diskKey) } func pingServer(cfg *config.ClientConfig) error { diff --git a/netclient/ncutils/encryption.go b/netclient/ncutils/encryption.go new file mode 100644 index 00000000..30f2ffa3 --- /dev/null +++ b/netclient/ncutils/encryption.go @@ -0,0 +1,109 @@ +package ncutils + +import ( + "bytes" + "crypto/rand" + "encoding/gob" + "fmt" + "io" + + "golang.org/x/crypto/nacl/box" +) + +const ( + chunkSize = 16128 // 16128 bytes max message size +) + +// BoxEncrypt - encrypts traffic box +func BoxEncrypt(message []byte, recipientPubKey *[32]byte, senderPrivateKey *[32]byte) ([]byte, error) { + var nonce [24]byte // 192 bits of randomization + if _, err := io.ReadFull(rand.Reader, nonce[:]); err != nil { + return nil, err + } + + encrypted := box.Seal(nonce[:], message, &nonce, recipientPubKey, senderPrivateKey) + return encrypted, nil +} + +// BoxDecrypt - decrypts traffic box +func BoxDecrypt(encrypted []byte, senderPublicKey *[32]byte, recipientPrivateKey *[32]byte) ([]byte, error) { + var decryptNonce [24]byte + copy(decryptNonce[:], encrypted[:24]) + decrypted, ok := box.Open(nil, encrypted[24:], &decryptNonce, senderPublicKey, recipientPrivateKey) + if !ok { + return nil, fmt.Errorf("could not decrypt message") + } + return decrypted, nil +} + +// Chunk - chunks a message and encrypts each chunk +func Chunk(message []byte, recipientPubKey *[32]byte, senderPrivateKey *[32]byte) ([]byte, error) { + var chunks [][]byte + for i := 0; i < len(message); i += chunkSize { + end := i + chunkSize + + // necessary check to avoid slicing beyond + // slice capacity + if end > len(message) { + end = len(message) + } + + encryptedMsgSlice, err := BoxEncrypt(message[i:end], recipientPubKey, senderPrivateKey) + if err != nil { + return nil, err + } + + chunks = append(chunks, encryptedMsgSlice) + } + + chunkedMsg, err := convertBytesToMsg(chunks) // encode the array into some bytes to decode on receiving end + if err != nil { + return nil, err + } + + return chunkedMsg, nil +} + +// DeChunk - "de" chunks and decrypts a message +func DeChunk(chunkedMsg []byte, senderPublicKey *[32]byte, recipientPrivateKey *[32]byte) ([]byte, error) { + chunks, err := convertMsgToBytes(chunkedMsg) + if err != nil { + return nil, err + } + + var totalMsg []byte + for i := range chunks { + decodedMsg, err := BoxDecrypt(chunks[i], senderPublicKey, recipientPrivateKey) + if err != nil { + return nil, err + } + totalMsg = append(totalMsg, decodedMsg...) + } + return totalMsg, nil +} + +// == private == + +// ConvertMsgToBytes - converts a message (MQ) to it's chunked version +// decode action +func convertMsgToBytes(msg []byte) ([][]byte, error) { + var buffer = bytes.NewBuffer(msg) + var dec = gob.NewDecoder(buffer) + var result [][]byte + var err = dec.Decode(&result) + if err != nil { + return nil, err + } + return result, err +} + +// ConvertBytesToMsg - converts the chunked message into a MQ message +// encode action +func convertBytesToMsg(b [][]byte) ([]byte, error) { + var buffer bytes.Buffer + var enc = gob.NewEncoder(&buffer) + if err := enc.Encode(b); err != nil { + return nil, err + } + return buffer.Bytes(), nil +} diff --git a/netclient/ncutils/netclientutils.go b/netclient/ncutils/netclientutils.go index a3d0d054..5f83463d 100644 --- a/netclient/ncutils/netclientutils.go +++ b/netclient/ncutils/netclientutils.go @@ -2,7 +2,6 @@ package ncutils import ( "bytes" - crand "crypto/rand" "crypto/tls" "encoding/gob" "errors" @@ -22,7 +21,6 @@ import ( "time" "github.com/gravitl/netmaker/models" - "golang.org/x/crypto/nacl/box" "golang.zx2c4.com/wireguard/wgctrl" "golang.zx2c4.com/wireguard/wgctrl/wgtypes" "google.golang.org/grpc" @@ -613,28 +611,6 @@ func ServerAddrSliceContains(slice []models.ServerAddr, item models.ServerAddr) return false } -// BoxEncrypt - encrypts traffic box -func BoxEncrypt(message []byte, recipientPubKey *[32]byte, senderPrivateKey *[32]byte) ([]byte, error) { - var nonce [24]byte // 192 bits of randomization - if _, err := io.ReadFull(crand.Reader, nonce[:]); err != nil { - return nil, err - } - - encrypted := box.Seal(nonce[:], message, &nonce, recipientPubKey, senderPrivateKey) - return encrypted, nil -} - -// BoxDecrypt - decrypts traffic box -func BoxDecrypt(encrypted []byte, senderPublicKey *[32]byte, recipientPrivateKey *[32]byte) ([]byte, error) { - var decryptNonce [24]byte - copy(decryptNonce[:], encrypted[:24]) - decrypted, ok := box.Open(nil, encrypted[24:], &decryptNonce, senderPublicKey, recipientPrivateKey) - if !ok { - return nil, fmt.Errorf("could not decrypt message") - } - return decrypted, nil -} - // MakeRandomString - generates a random string of len n func MakeRandomString(n int) string { sb := strings.Builder{} From 98609ac61e030fbe88551466f265bebf3c89450f Mon Sep 17 00:00:00 2001 From: 0xdcarns Date: Mon, 14 Feb 2022 20:04:30 -0500 Subject: [PATCH 2/4] implmented chunking --- mq/mq.go | 9 +++++---- netclient/ncutils/encryption.go | 33 +++++++++++++++++---------------- 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/mq/mq.go b/mq/mq.go index cd92c058..8c64ba10 100644 --- a/mq/mq.go +++ b/mq/mq.go @@ -53,12 +53,13 @@ func Ping(client mqtt.Client, msg mqtt.Message) { } _, decryptErr := decryptMsg(&node, msg.Payload()) if decryptErr != nil { - logger.Log(0, "error updating node ", node.ID, err.Error()) + logger.Log(0, "error decrypting when updating node ", node.ID, decryptErr.Error()) return } node.SetLastCheckIn() if err := logic.UpdateNode(&node, &node); err != nil { - logger.Log(0, "error updating node ", err.Error()) + logger.Log(0, "error updating node", node.Name, node.ID, " on checkin", err.Error()) + return } logger.Log(3, "ping processed for node", node.ID) // --TODO --set client version once feature is implemented. @@ -84,7 +85,6 @@ func UpdateNode(client mqtt.Client, msg mqtt.Message) { logger.Log(1, "failed to decrypt message for node ", id, decryptErr.Error()) return } - logger.Log(1, "Update Node Handler", id) var newNode models.Node if err := json.Unmarshal(decrypted, &newNode); err != nil { logger.Log(1, "error unmarshaling payload ", err.Error()) @@ -92,12 +92,13 @@ func UpdateNode(client mqtt.Client, msg mqtt.Message) { } if err := logic.UpdateNode(¤tNode, &newNode); err != nil { logger.Log(1, "error saving node", err.Error()) + return } if err := PublishPeerUpdate(&newNode); err != nil { logger.Log(1, "error publishing peer update ", err.Error()) return } - logger.Log(1, "no need to update peers") + logger.Log(1, "Updated node", id, newNode.Name) }() } diff --git a/netclient/ncutils/encryption.go b/netclient/ncutils/encryption.go index 30f2ffa3..207a2c7f 100644 --- a/netclient/ncutils/encryption.go +++ b/netclient/ncutils/encryption.go @@ -3,7 +3,6 @@ package ncutils import ( "bytes" "crypto/rand" - "encoding/gob" "fmt" "io" @@ -11,7 +10,7 @@ import ( ) const ( - chunkSize = 16128 // 16128 bytes max message size + chunkSize = 16000 // 16128 bytes max message size ) // BoxEncrypt - encrypts traffic box @@ -66,7 +65,7 @@ func Chunk(message []byte, recipientPubKey *[32]byte, senderPrivateKey *[32]byte // DeChunk - "de" chunks and decrypts a message func DeChunk(chunkedMsg []byte, senderPublicKey *[32]byte, recipientPrivateKey *[32]byte) ([]byte, error) { - chunks, err := convertMsgToBytes(chunkedMsg) + chunks, err := convertMsgToBytes(chunkedMsg) // convert the message to it's original chunks form if err != nil { return nil, err } @@ -84,26 +83,28 @@ func DeChunk(chunkedMsg []byte, senderPublicKey *[32]byte, recipientPrivateKey * // == private == +var splitKey = []byte("|(,)(,)|") + // ConvertMsgToBytes - converts a message (MQ) to it's chunked version // decode action func convertMsgToBytes(msg []byte) ([][]byte, error) { - var buffer = bytes.NewBuffer(msg) - var dec = gob.NewDecoder(buffer) - var result [][]byte - var err = dec.Decode(&result) - if err != nil { - return nil, err - } - return result, err + splitMsg := bytes.Split(msg, splitKey) + return splitMsg, nil } // ConvertBytesToMsg - converts the chunked message into a MQ message // encode action func convertBytesToMsg(b [][]byte) ([]byte, error) { - var buffer bytes.Buffer - var enc = gob.NewEncoder(&buffer) - if err := enc.Encode(b); err != nil { - return nil, err + // var totalSize = len(b) * len(splitKey) + // for _, buf := range b { + // totalSize += len(buf) + // } + var buffer []byte // allocate a buffer with adequate sizing + for i := range b { // append bytes to it with key + buffer = append(buffer, b[i]...) + if i != len(b)-1 { + buffer = append(buffer, splitKey...) + } } - return buffer.Bytes(), nil + return buffer, nil } From 96e17c9b17477ca1407eeefca8d5cd91f82f8988 Mon Sep 17 00:00:00 2001 From: 0xdcarns Date: Mon, 14 Feb 2022 20:07:22 -0500 Subject: [PATCH 3/4] comment cleanup --- netclient/ncutils/encryption.go | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/netclient/ncutils/encryption.go b/netclient/ncutils/encryption.go index 207a2c7f..2976c913 100644 --- a/netclient/ncutils/encryption.go +++ b/netclient/ncutils/encryption.go @@ -10,7 +10,7 @@ import ( ) const ( - chunkSize = 16000 // 16128 bytes max message size + chunkSize = 16000 // 16000 bytes max message size ) // BoxEncrypt - encrypts traffic box @@ -30,7 +30,7 @@ func BoxDecrypt(encrypted []byte, senderPublicKey *[32]byte, recipientPrivateKey copy(decryptNonce[:], encrypted[:24]) decrypted, ok := box.Open(nil, encrypted[24:], &decryptNonce, senderPublicKey, recipientPrivateKey) if !ok { - return nil, fmt.Errorf("could not decrypt message") + return nil, fmt.Errorf("could not decrypt message, %v", encrypted) } return decrypted, nil } @@ -41,8 +41,6 @@ func Chunk(message []byte, recipientPubKey *[32]byte, senderPrivateKey *[32]byte for i := 0; i < len(message); i += chunkSize { end := i + chunkSize - // necessary check to avoid slicing beyond - // slice capacity if end > len(message) { end = len(message) } @@ -95,10 +93,7 @@ func convertMsgToBytes(msg []byte) ([][]byte, error) { // ConvertBytesToMsg - converts the chunked message into a MQ message // encode action func convertBytesToMsg(b [][]byte) ([]byte, error) { - // var totalSize = len(b) * len(splitKey) - // for _, buf := range b { - // totalSize += len(buf) - // } + var buffer []byte // allocate a buffer with adequate sizing for i := range b { // append bytes to it with key buffer = append(buffer, b[i]...) From d9e63389121eb539158cf42254fdfad523a54364 Mon Sep 17 00:00:00 2001 From: 0xdcarns Date: Tue, 15 Feb 2022 10:22:11 -0500 Subject: [PATCH 4/4] added compatibility with 0.10.0 clients --- mq/util.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/mq/util.go b/mq/util.go index 83186261..8c7b2e01 100644 --- a/mq/util.go +++ b/mq/util.go @@ -2,6 +2,7 @@ package mq import ( "fmt" + "strings" "github.com/gravitl/netmaker/logic" "github.com/gravitl/netmaker/models" @@ -26,6 +27,10 @@ func decryptMsg(node *models.Node, msg []byte) ([]byte, error) { return nil, err } + if strings.Contains(node.Version, "0.10.0") { + return ncutils.BoxDecrypt(msg, nodePubTKey, serverPrivTKey) + } + return ncutils.DeChunk(msg, nodePubTKey, serverPrivTKey) } @@ -46,6 +51,10 @@ func encryptMsg(node *models.Node, msg []byte) ([]byte, error) { return nil, err } + if strings.Contains(node.Version, "0.10.0") { + return ncutils.BoxEncrypt(msg, nodePubKey, serverPrivKey) + } + return ncutils.Chunk(msg, nodePubKey, serverPrivKey) }