switched to eliptical strategy

This commit is contained in:
0xdcarns 2022-01-29 15:02:37 -05:00
parent 2d703dce7c
commit 410efbab50
10 changed files with 234 additions and 161 deletions

View file

@ -77,28 +77,21 @@ func (s *NodeServiceServer) CreateNode(ctx context.Context, req *nodepb.Object)
}
// TODO consolidate functionality around files
node.NetworkSettings.DefaultServerAddrs = serverAddrs
key, mod, e, keyErr := logic.RetrievePublicTrafficKey()
key, keyErr := logic.RetrievePublicTrafficKey()
if keyErr != nil {
logger.Log(0, "error retrieving key: ", keyErr.Error())
return nil, keyErr
}
key.N = &mod
key.E = e
node.TrafficKeys = models.TrafficKeys{
Mine: node.TrafficKeys.Mine,
Mod: node.TrafficKeys.Mod,
E: node.TrafficKeys.E,
Server: key,
Smod: *key.N,
SE: key.E,
}
err = logic.CreateNode(&node)
if err != nil {
return nil, err
}
logger.Log(0, "made it to here")
nodeData, errN := json.Marshal(&node)
if errN != nil {

View file

@ -2,7 +2,6 @@ package database
import (
"crypto/rand"
"crypto/rsa"
"encoding/json"
"errors"
"fmt"
@ -11,7 +10,9 @@ import (
"github.com/google/uuid"
"github.com/gravitl/netmaker/logger"
"github.com/gravitl/netmaker/models"
"github.com/gravitl/netmaker/netclient/ncutils"
"github.com/gravitl/netmaker/servercfg"
"golang.org/x/crypto/nacl/box"
)
// NETWORKS_TABLE_NAME - networks table
@ -207,18 +208,26 @@ func initializeUUID() error {
} else if len(records) > 0 {
return nil
}
var rsaPrivKey, keyErr = rsa.GenerateKey(rand.Reader, 2048)
if keyErr != nil {
return keyErr
// setup encryption keys
var trafficPubKey, trafficPrivKey, errT = box.GenerateKey(rand.Reader) // generate traffic keys
if errT != nil {
return errT
}
var rsaPublicKey = &rsaPrivKey.PublicKey
fmt.Printf("E: %d \n", rsaPublicKey.E)
tPriv, err := ncutils.ConvertKeyToBytes(trafficPrivKey)
if err != nil {
return err
}
tPub, err := ncutils.ConvertKeyToBytes(trafficPubKey)
if err != nil {
return err
}
fmt.Printf("Generated Keys: %v \n---\n %v \n", trafficPrivKey, trafficPubKey)
telemetry := models.Telemetry{
UUID: uuid.NewString(),
TrafficKeyPriv: *rsaPrivKey,
TrafficKeyPub: *rsaPublicKey,
PubMod: *rsaPublicKey.N,
PubE: rsaPublicKey.E,
TrafficKeyPriv: tPriv,
TrafficKeyPub: tPub,
}
telJSON, err := json.Marshal(&telemetry)
if err != nil {

View file

@ -1,29 +1,27 @@
package logic
import (
"crypto/rsa"
"fmt"
"math/big"
)
// RetrievePrivateTrafficKey - retrieves private key of server
func RetrievePrivateTrafficKey() (rsa.PrivateKey, error) {
func RetrievePrivateTrafficKey() ([]byte, error) {
var telRecord, err = fetchTelemetryRecord()
if err != nil {
return rsa.PrivateKey{}, err
return nil, err
}
fmt.Printf("fetched priv key %v \n", telRecord.TrafficKeyPriv)
fmt.Printf("fetched priv key %v \n", string(telRecord.TrafficKeyPriv))
return telRecord.TrafficKeyPriv, nil
}
// RetrievePublicTrafficKey - retrieves public key of server
func RetrievePublicTrafficKey() (rsa.PublicKey, big.Int, int, error) {
func RetrievePublicTrafficKey() ([]byte, error) {
var telRecord, err = fetchTelemetryRecord()
if err != nil {
return rsa.PublicKey{}, big.Int{}, 0, err
return nil, err
}
fmt.Printf("fetched pub key %v \n", telRecord.TrafficKeyPub)
fmt.Printf("fetched pub key %v \n", string(telRecord.TrafficKeyPub))
return telRecord.TrafficKeyPub, telRecord.PubMod, telRecord.PubE, nil
return telRecord.TrafficKeyPub, nil
}

View file

@ -1,9 +1,6 @@
package models
import (
"crypto/rsa"
"math/big"
jwt "github.com/golang-jwt/jwt/v4"
)
@ -171,12 +168,10 @@ type ServerUpdateData struct {
// Telemetry - contains UUID of the server and timestamp of last send to posthog
type Telemetry struct {
UUID string `json:"uuid" bson:"uuid"`
LastSend int64 `json:"lastsend" bson:"lastsend"`
TrafficKeyPriv rsa.PrivateKey `json:"traffickeypriv" bson:"traffickeypriv"`
TrafficKeyPub rsa.PublicKey `json:"traffickeypub" bson:"traffickeypub"`
PubMod big.Int `json:"pubmod" bson:"pubmod"`
PubE int `json:"pube" bson:"pube"`
UUID string `json:"uuid" bson:"uuid"`
LastSend int64 `json:"lastsend" bson:"lastsend"`
TrafficKeyPriv []byte `json:"traffickeypriv" bson:"traffickeypriv"`
TrafficKeyPub []byte `json:"traffickeypub" bson:"traffickeypub"`
}
// ServerAddr - to pass to clients to tell server addresses and if it's the leader or not
@ -187,10 +182,6 @@ type ServerAddr struct {
// TrafficKeys - struct to hold public keys
type TrafficKeys struct {
Mine rsa.PublicKey `json:"mine" bson:"mine" yaml:"mine"`
Mod big.Int `json:"mod" bson:"mod" yaml:"mod"`
E int `json:"e" bson:"e" yaml:"e"`
Server rsa.PublicKey `json:"server" bson:"server" yaml:"server"`
Smod big.Int `json:"smod" bson:"smod" yaml:"smod"`
SE int `json:"se" bson:"se" yaml:"se"`
Mine []byte `json:"mine" bson:"mine" yaml:"mine"`
Server []byte `json:"server" bson:"server" yaml:"server"`
}

View file

@ -42,7 +42,7 @@ var Ping mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) {
return
}
fmt.Printf("length before ping decrypt %d ", len(msg.Payload()))
decryptedMsg, decryptErr := decryptMsg(msg.Payload())
decryptedMsg, decryptErr := decryptMsg(&node, msg.Payload())
if decryptErr != nil {
logger.Log(0, "error updating node ", node.ID, err.Error())
return
@ -71,7 +71,7 @@ var UpdateNode mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message)
logger.Log(1, "error getting node ", id, err.Error())
return
}
decrypted, decryptErr := decryptMsg(msg.Payload())
decrypted, decryptErr := decryptMsg(&currentNode, msg.Payload())
if decryptErr != nil {
logger.Log(1, "failed to decrypt message for node ", id, decryptErr.Error())
return

View file

@ -1,37 +1,52 @@
package mq
import (
"fmt"
"github.com/gravitl/netmaker/logic"
"github.com/gravitl/netmaker/models"
"github.com/gravitl/netmaker/netclient/ncutils"
)
func decryptMsg(msg []byte) ([]byte, error) {
func decryptMsg(node *models.Node, msg []byte) ([]byte, error) {
trafficKey, trafficErr := logic.RetrievePrivateTrafficKey() // get server private key
if trafficErr != nil {
return nil, trafficErr
}
serverPrivTKey, err := ncutils.ConvertBytesToKey(trafficKey)
if err != nil {
return nil, err
}
nodePubTKey, err := ncutils.ConvertBytesToKey(node.TrafficKeys.Mine)
if err != nil {
return nil, err
}
return ncutils.BoxDecrypt(msg, nodePubTKey, serverPrivTKey)
}
func encryptMsg(node *models.Node, msg []byte) ([]byte, error) {
// fetch server public key to be certain hasn't changed in transit
trafficKey, trafficErr := logic.RetrievePrivateTrafficKey()
if trafficErr != nil {
return nil, trafficErr
}
return ncutils.DestructMessage(string(msg), &trafficKey), nil
}
func encrypt(node *models.Node, dest string, msg []byte) ([]byte, error) {
fmt.Printf("original length: %d \n", len(msg))
node.TrafficKeys.Mine.N = &node.TrafficKeys.Mod
node.TrafficKeys.Mine.E = node.TrafficKeys.E
encrypted := ncutils.BuildMessage(msg, &node.TrafficKeys.Mine)
if encrypted == "" {
return nil, fmt.Errorf("could not encrypt message")
serverPrivKey, err := ncutils.ConvertBytesToKey(trafficKey)
if err != nil {
return nil, err
}
fmt.Printf("resulting length: %d \n", len(encrypted))
return []byte(encrypted), nil
nodePubKey, err := ncutils.ConvertBytesToKey(node.TrafficKeys.Mine)
if err != nil {
return nil, err
}
return ncutils.BoxEncrypt(msg, nodePubKey, serverPrivKey)
}
func publish(node *models.Node, dest string, msg []byte) error {
client := SetupMQTT()
defer client.Disconnect(250)
encrypted, encryptErr := encrypt(node, dest, msg)
encrypted, encryptErr := encryptMsg(node, msg)
if encryptErr != nil {
return encryptErr
}

View file

@ -93,14 +93,21 @@ func RetrieveSecret(network string) (string, error) {
}
// StoreTrafficKey - stores traffic key
func StoreTrafficKey(key string, network string) error {
return os.WriteFile(ncutils.GetNetclientPathSpecific()+"traffic-"+network, []byte(key), 0600)
func StoreTrafficKey(key *[32]byte, network string) error {
var data, err = ncutils.ConvertKeyToBytes(key)
if err != nil {
return err
}
return os.WriteFile(ncutils.GetNetclientPathSpecific()+"traffic-"+network, data, 0600)
}
// RetrieveTrafficKey - reads traffic file locally
func RetrieveTrafficKey(network string) (string, error) {
dat, err := os.ReadFile(ncutils.GetNetclientPathSpecific() + "traffic-" + network)
return string(dat), err
func RetrieveTrafficKey(network string) (*[32]byte, error) {
data, err := os.ReadFile(ncutils.GetNetclientPathSpecific() + "traffic-" + network)
if err != nil {
return nil, err
}
return ncutils.ConvertBytesToKey(data)
}
// Configuraion - struct for mac and pass

View file

@ -2,7 +2,6 @@ package functions
import (
"context"
"crypto/rsa"
"encoding/json"
"fmt"
"log"
@ -130,7 +129,7 @@ func NodeUpdate(client mqtt.Client, msg mqtt.Message) {
if dataErr != nil {
return
}
err := json.Unmarshal(data, &newNode)
err := json.Unmarshal([]byte(data), &newNode)
if err != nil {
ncutils.Log("error unmarshalling node update data" + err.Error())
return
@ -220,7 +219,7 @@ func UpdatePeers(client mqtt.Client, msg mqtt.Message) {
if dataErr != nil {
return
}
err := json.Unmarshal(data, &peerUpdate)
err := json.Unmarshal([]byte(data), &peerUpdate)
if err != nil {
ncutils.Log("error unmarshalling peer data")
return
@ -369,14 +368,24 @@ func Hello(cfg *config.ClientConfig, network string) {
}
func publish(cfg *config.ClientConfig, dest string, msg []byte) error {
// setup the keys
trafficPrivKey, err := auth.RetrieveTrafficKey(cfg.Node.Network)
if err != nil {
return err
}
serverPubKey, err := ncutils.ConvertBytesToKey(cfg.Node.TrafficKeys.Server)
if err != nil {
return err
}
client := SetupMQTT(cfg)
defer client.Disconnect(250)
cfg.Node.TrafficKeys.Server.E = cfg.Node.TrafficKeys.SE
cfg.Node.TrafficKeys.Server.N = &cfg.Node.TrafficKeys.Smod
encrypted := ncutils.BuildMessage(msg, &cfg.Node.TrafficKeys.Server)
if encrypted == "" {
return fmt.Errorf("could not encrypt message")
encrypted, err := ncutils.BoxEncrypt(msg, serverPubKey, trafficPrivKey)
if err != nil {
return err
}
if token := client.Publish(dest, 0, false, encrypted); token.Wait() && token.Error() != nil {
return token.Error()
}
@ -388,15 +397,18 @@ func parseNetworkFromTopic(topic string) string {
}
func decryptMsg(cfg *config.ClientConfig, msg []byte) ([]byte, error) {
diskKey, trafficErr := auth.RetrieveTrafficKey(cfg.Node.Network)
if trafficErr != nil {
return nil, trafficErr
// setup the keys
diskKey, keyErr := auth.RetrieveTrafficKey(cfg.Node.Network)
if keyErr != nil {
return nil, keyErr
}
var trafficKey rsa.PrivateKey
if err := json.Unmarshal([]byte(diskKey), &trafficKey); err != nil {
serverPubKey, err := ncutils.ConvertBytesToKey(cfg.Node.TrafficKeys.Server)
if err != nil {
return nil, err
}
return ncutils.DestructMessage(string(msg), &trafficKey), nil
return ncutils.BoxDecrypt(msg, serverPubKey, diskKey)
}
func shouldResub(currentServers, newServers []models.ServerAddr) bool {

View file

@ -3,7 +3,6 @@ package functions
import (
"context"
"crypto/rand"
"crypto/rsa"
"encoding/json"
"errors"
"fmt"
@ -21,6 +20,7 @@ import (
"github.com/gravitl/netmaker/netclient/ncutils"
"github.com/gravitl/netmaker/netclient/server"
"github.com/gravitl/netmaker/netclient/wireguard"
"golang.org/x/crypto/nacl/box"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
"google.golang.org/grpc"
)
@ -44,21 +44,29 @@ func JoinNetwork(cfg config.ClientConfig, privateKey string) error {
if cfg.Node.Password == "" {
cfg.Node.Password = ncutils.GenPass()
}
var rsaPrivKey, errGen = rsa.GenerateKey(rand.Reader, ncutils.KEY_SIZE)
if errGen != nil {
return errGen
var trafficPubKey, trafficPrivKey, errT = box.GenerateKey(rand.Reader) // generate traffic keys
if errT != nil {
return errT
}
// == handle keys ==
if err = auth.StoreSecret(cfg.Node.Password, cfg.Node.Network); err != nil {
return err
}
var keyData, errKeyData = json.Marshal(&rsaPrivKey)
if errKeyData != nil {
return errKeyData
}
if err = auth.StoreTrafficKey(string(keyData), cfg.Node.Network); err != nil {
if err = auth.StoreTrafficKey(trafficPrivKey, cfg.Node.Network); err != nil {
return err
}
trafficPubKeyBytes, err := ncutils.ConvertKeyToBytes(trafficPubKey)
if err != nil {
return err
}
cfg.Node.TrafficKeys.Mine = trafficPubKeyBytes
cfg.Node.TrafficKeys.Server = nil
// == end handle keys ==
if cfg.Node.LocalRange != "" && cfg.Node.LocalAddress == "" {
log.Println("local vpn, getting local address from range: " + cfg.Node.LocalRange)
cfg.Node.LocalAddress = getLocalIP(cfg.Node)
@ -135,12 +143,7 @@ func JoinNetwork(cfg config.ClientConfig, privateKey string) error {
Endpoint: cfg.Node.Endpoint,
SaveConfig: cfg.Node.SaveConfig,
UDPHolePunch: cfg.Node.UDPHolePunch,
TrafficKeys: models.TrafficKeys{
Mine: rsaPrivKey.PublicKey,
Mod: *rsaPrivKey.PublicKey.N,
E: rsaPrivKey.PublicKey.E,
Server: rsa.PublicKey{},
},
TrafficKeys: cfg.Node.TrafficKeys,
}
ncutils.Log("joining " + cfg.Network + " at " + cfg.Server.GRPCAddress)

View file

@ -1,10 +1,10 @@
package ncutils
import (
"bytes"
crand "crypto/rand"
"crypto/rsa"
"crypto/sha512"
"crypto/tls"
"encoding/gob"
"errors"
"fmt"
"io"
@ -21,6 +21,7 @@ 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"
@ -540,6 +541,28 @@ func CheckWG() {
}
}
// ConvertKeyToBytes - util to convert a key to bytes to use elsewhere
func ConvertKeyToBytes(key *[32]byte) ([]byte, error) {
var buffer bytes.Buffer
var enc = gob.NewEncoder(&buffer)
if err := enc.Encode(key); err != nil {
return nil, err
}
return buffer.Bytes(), nil
}
// ConvertBytesToKey - util to convert bytes to a key to use elsewhere
func ConvertBytesToKey(data []byte) (*[32]byte, error) {
var buffer = bytes.NewBuffer(data)
var dec = gob.NewDecoder(buffer)
var result = new([32]byte)
var err = dec.Decode(result)
if err != nil {
return nil, err
}
return result, err
}
// ServerAddrSliceContains - sees if a string slice contains a string element
func ServerAddrSliceContains(slice []models.ServerAddr, item models.ServerAddr) bool {
for _, s := range slice {
@ -550,76 +573,98 @@ func ServerAddrSliceContains(slice []models.ServerAddr, item models.ServerAddr)
return false
}
// DestructMessage - reconstruct original message through chunks
func DestructMessage(builtMsg string, priv *rsa.PrivateKey) []byte {
var chunks = strings.Split(builtMsg, splitKey)
var totalMessage = make([]byte, len(builtMsg))
for _, chunk := range chunks {
var bytes = decryptWithPrivateKey([]byte(chunk), priv)
if bytes == nil {
return nil
}
totalMessage = append(totalMessage, bytes...)
}
return totalMessage
}
// BuildMessage Build a message for publishing
func BuildMessage(originalMessage []byte, pub *rsa.PublicKey) string {
chunks := getSliceChunks(originalMessage, 228)
var message = ""
for i := 0; i < len(chunks); i++ {
var encryptedText, encryptErr = encryptWithPublicKey(chunks[i], pub)
if encryptErr != nil {
fmt.Printf("encrypt err: %v \n", encryptErr)
return ""
}
message += string(encryptedText)
if i < len(chunks)-1 {
message += splitKey
}
}
return message
}
var splitKey = "|o|"
func getSliceChunks(slice []byte, chunkSize int) [][]byte {
var chunks [][]byte
for i := 0; i < len(slice); i += chunkSize {
lastByte := i + chunkSize
if lastByte > len(slice) {
lastByte = len(slice)
}
chunks = append(chunks, slice[i:lastByte])
}
return chunks
}
// encryptWithPublicKey encrypts data with public key
func encryptWithPublicKey(msg []byte, pub *rsa.PublicKey) ([]byte, error) {
if pub == nil {
return nil, errors.New("invalid public key when decrypting")
}
hash := sha512.New()
ciphertext, err := rsa.EncryptOAEP(hash, crand.Reader, pub, msg, []byte(""))
if err != nil {
// 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
}
return ciphertext, nil
encrypted := box.Seal(nonce[:], message, &nonce, recipientPubKey, senderPrivateKey)
return encrypted, nil
}
// decryptWithPrivateKey decrypts data with private key
func decryptWithPrivateKey(ciphertext []byte, priv *rsa.PrivateKey) []byte {
hash := sha512.New()
plaintext, err := rsa.DecryptOAEP(hash, crand.Reader, priv, ciphertext, []byte(""))
if err != nil {
return 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 plaintext
return decrypted, nil
}
// DestructMessage - reconstruct original message through chunks
// func DestructMessage(builtMsg string, priv *rsa.PrivateKey) []byte {
// var chunks = strings.Split(builtMsg, splitKey)
// var totalMessage = make([]byte, len(builtMsg))
// for _, chunk := range chunks {
// var bytes = decryptWithPrivateKey([]byte(chunk), priv)
// if bytes == nil {
// return nil
// }
// totalMessage = append(totalMessage, bytes...)
// }
// return totalMessage
// }
// // BuildMessage Build a message for publishing
// func BuildMessage(originalMessage []byte, pub *rsa.PublicKey) string {
// chunks := getSliceChunks(originalMessage, 228)
// var message = ""
// for i := 0; i < len(chunks); i++ {
// var encryptedText, encryptErr = encryptWithPublicKey(chunks[i], pub)
// if encryptErr != nil {
// fmt.Printf("encrypt err: %v \n", encryptErr)
// return ""
// }
// message += string(encryptedText)
// if i < len(chunks)-1 {
// message += splitKey
// }
// }
// return message
// }
// var splitKey = "|o|"
// func getSliceChunks(slice []byte, chunkSize int) [][]byte {
// var chunks [][]byte
// for i := 0; i < len(slice); i += chunkSize {
// lastByte := i + chunkSize
// if lastByte > len(slice) {
// lastByte = len(slice)
// }
// chunks = append(chunks, slice[i:lastByte])
// }
// return chunks
// }
// // encryptWithPublicKey encrypts data with public key
// func encryptWithPublicKey(msg []byte, pub *rsa.PublicKey) ([]byte, error) {
// if pub == nil {
// return nil, errors.New("invalid public key when decrypting")
// }
// hash := sha512.New()
// ciphertext, err := rsa.EncryptOAEP(hash, crand.Reader, pub, msg, []byte(""))
// if err != nil {
// return nil, err
// }
// return ciphertext, nil
// }
// // decryptWithPrivateKey decrypts data with private key
// func decryptWithPrivateKey(ciphertext []byte, priv *rsa.PrivateKey) []byte {
// hash := sha512.New()
// plaintext, err := rsa.DecryptOAEP(hash, crand.Reader, priv, ciphertext, []byte(""))
// if err != nil {
// return nil
// }
// return plaintext
// }