Browse Source

:gear: Allow to specify different sealers

Ettore Di Giacinto 3 years ago
parent
commit
b7cca54aa1

+ 2 - 0
cmd/util.go

@@ -25,6 +25,7 @@ import (
 	dht "github.com/libp2p/go-libp2p-kad-dht"
 	"github.com/mudler/edgevpn/internal"
 	"github.com/mudler/edgevpn/pkg/blockchain"
+	"github.com/mudler/edgevpn/pkg/crypto"
 	"github.com/mudler/edgevpn/pkg/discovery"
 	"github.com/mudler/edgevpn/pkg/logger"
 	node "github.com/mudler/edgevpn/pkg/node"
@@ -237,6 +238,7 @@ func cliToOpts(c *cli.Context) ([]node.Option, []vpn.Option, *logger.Logger) {
 		node.WithBlacklist(c.StringSlice("blacklist")...),
 		node.LibP2PLogLevel(libp2plvl),
 		node.WithInterfaceAddress(address),
+		node.WithSealer(&crypto.AESSealer{}),
 		node.FromBase64(mDNS, dhtE, token, dhtOpts...),
 		node.FromYaml(mDNS, dhtE, config, dhtOpts...),
 	}

+ 1 - 7
pkg/utils/crypto.go → pkg/crypto/aes.go

@@ -13,12 +13,11 @@
 // You should have received a copy of the GNU General Public License along
 // with this program; if not, see <http://www.gnu.org/licenses/>.
 
-package utils
+package crypto
 
 import (
 	"crypto/aes"
 	"crypto/cipher"
-	"crypto/md5"
 	"crypto/rand"
 	"encoding/hex"
 	"errors"
@@ -77,8 +76,3 @@ func AESDecrypt(text string, key *[32]byte) (plaintext string, err error) {
 
 	return string(decodedtext), err
 }
-
-func MD5(text string) string {
-	hash := md5.Sum([]byte(text))
-	return hex.EncodeToString(hash[:])
-}

+ 3 - 2
pkg/utils/crypto_test.go → pkg/crypto/aes_test.go

@@ -13,13 +13,14 @@
 // You should have received a copy of the GNU General Public License along
 // with this program; if not, see <http://www.gnu.org/licenses/>.
 
-package utils_test
+package crypto_test
 
 import (
+	. "github.com/mudler/edgevpn/pkg/utils"
 	. "github.com/onsi/ginkgo"
 	. "github.com/onsi/gomega"
 
-	. "github.com/mudler/edgevpn/pkg/utils"
+	. "github.com/mudler/edgevpn/pkg/crypto"
 )
 
 var _ = Describe("Crypto utilities", func() {

+ 28 - 0
pkg/crypto/crypto_suite_test.go

@@ -0,0 +1,28 @@
+// Copyright © 2022 Ettore Di Giacinto <[email protected]>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, see <http://www.gnu.org/licenses/>.
+
+package crypto_test
+
+import (
+	"testing"
+
+	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/gomega"
+)
+
+func TestCrypto(t *testing.T) {
+	RegisterFailHandler(Fail)
+	RunSpecs(t, "Crypto Suite")
+}

+ 27 - 0
pkg/crypto/md5.go

@@ -0,0 +1,27 @@
+// Copyright © 2021-2022 Ettore Di Giacinto <[email protected]>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, see <http://www.gnu.org/licenses/>.
+
+package crypto
+
+import (
+	"crypto/md5"
+	"encoding/hex"
+)
+
+// MD5 is just syntax sugar around crypto/md5
+func MD5(text string) string {
+	hash := md5.Sum([]byte(text))
+	return hex.EncodeToString(hash[:])
+}

+ 30 - 0
pkg/crypto/sealer_aes.go

@@ -0,0 +1,30 @@
+// Copyright © 2021-2022 Ettore Di Giacinto <[email protected]>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, see <http://www.gnu.org/licenses/>.
+
+package crypto
+
+type AESSealer struct{}
+
+func (*AESSealer) Seal(message, key string) (encoded string, err error) {
+	enckey := [32]byte{}
+	copy(enckey[:], key)
+	return AESEncrypt(message, &enckey)
+}
+
+func (*AESSealer) Unseal(message, key string) (decoded string, err error) {
+	enckey := [32]byte{}
+	copy(enckey[:], key)
+	return AESDecrypt(message, &enckey)
+}

+ 56 - 0
pkg/crypto/sealer_test.go

@@ -0,0 +1,56 @@
+// Copyright © 2022 Ettore Di Giacinto <[email protected]>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, see <http://www.gnu.org/licenses/>.
+
+package crypto_test
+
+import (
+	. "github.com/mudler/edgevpn/pkg/utils"
+	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/gomega"
+
+	. "github.com/mudler/edgevpn/pkg/crypto"
+)
+
+var _ = Describe("Crypto utilities", func() {
+	Context("AESSealer", func() {
+		It("Encode/decode", func() {
+			key := RandStringRunes(32)
+			message := "foo"
+
+			s := &AESSealer{}
+
+			encoded, err := s.Seal(message, key)
+			Expect(err).ToNot(HaveOccurred())
+			Expect(encoded).ToNot(Equal(key))
+			Expect(len(encoded)).To(Equal(62))
+
+			// Encode again
+			encoded2, err := s.Seal(message, key)
+			Expect(err).ToNot(HaveOccurred())
+
+			// should differ
+			Expect(encoded2).ToNot(Equal(encoded))
+
+			// Decrypt and check
+			decoded, err := s.Unseal(encoded, key)
+			Expect(err).ToNot(HaveOccurred())
+			Expect(decoded).To(Equal(message))
+
+			decoded, err = s.Unseal(encoded2, key)
+			Expect(err).ToNot(HaveOccurred())
+			Expect(decoded).To(Equal(message))
+		})
+	})
+})

+ 0 - 27
pkg/hub/message.go

@@ -15,11 +15,6 @@
 
 package hub
 
-import (
-	"github.com/mudler/edgevpn/pkg/utils"
-	"github.com/pkg/errors"
-)
-
 // Message gets converted to/from JSON and sent in the body of pubsub messages.
 type Message struct {
 	Message  string
@@ -48,28 +43,6 @@ func NewMessage(s string) *Message {
 	return &Message{Message: s}
 }
 
-func (m *Message) Seal(key string) error {
-	enckey := [32]byte{}
-	copy(enckey[:], key)
-	enc, err := utils.AESEncrypt(m.Message, &enckey)
-	if err != nil {
-		return errors.Wrap(err, "while sealing message")
-	}
-	m.Message = enc
-	return nil
-}
-
-func (m *Message) Unseal(key string) error {
-	enckey := [32]byte{}
-	copy(enckey[:], key)
-	dec, err := utils.AESDecrypt(m.Message, &enckey)
-	if err != nil {
-		return errors.Wrapf(err, "while unsealing message from peer: %s", m.SenderID)
-	}
-	m.Message = dec
-	return nil
-}
-
 func (m *Message) Copy() *Message {
 	copy := *m
 	return &copy

+ 7 - 0
pkg/node/config.go

@@ -68,6 +68,13 @@ type Config struct {
 	DiscoveryBootstrapPeers                                         discovery.AddrList
 
 	Whitelist, Blacklist []string
+
+	Sealer Sealer
+}
+
+type Sealer interface {
+	Seal(string, string) (string, error)
+	Unseal(string, string) (string, error)
 }
 
 // NetworkService is a service running over the network. It takes a context, a node and a ledger

+ 6 - 2
pkg/node/connection.go

@@ -126,18 +126,22 @@ func (e *Node) handleEvents(ctx context.Context) {
 				continue
 			}
 			c := m.Copy()
-			if err := c.Seal(e.sealkey()); err != nil {
+			str, err := e.config.Sealer.Seal(c.Message, e.sealkey())
+			if err != nil {
 				e.config.Logger.Warn(err.Error())
 			}
+			c.Message = str
 			e.handleOutgoingMessage(c)
 		case m := <-e.HubRoom.Messages:
 			if m == nil {
 				continue
 			}
 			c := m.Copy()
-			if err := c.Unseal(e.sealkey()); err != nil {
+			str, err := e.config.Sealer.Unseal(c.Message, e.sealkey())
+			if err != nil {
 				e.config.Logger.Warn(err.Error())
 			}
+			c.Message = str
 			e.handleReceivedMessage(c)
 		case <-ctx.Done():
 			return

+ 2 - 0
pkg/node/node.go

@@ -25,6 +25,7 @@ import (
 	"github.com/libp2p/go-libp2p-core/network"
 	"github.com/libp2p/go-libp2p/p2p/net/conngater"
 
+	"github.com/mudler/edgevpn/pkg/crypto"
 	protocol "github.com/mudler/edgevpn/pkg/protocol"
 
 	pubsub "github.com/libp2p/go-libp2p-pubsub"
@@ -58,6 +59,7 @@ func New(p ...Option) *Node {
 		SealKeyLength:            12,
 		Options:                  defaultLibp2pOptions,
 		Logger:                   logger.New(log.LevelDebug),
+		Sealer:                   &crypto.AESSealer{},
 	}
 	c.Apply(p...)
 

+ 7 - 0
pkg/node/options.go

@@ -40,6 +40,13 @@ func WithLibp2pOptions(i ...libp2p.Option) func(cfg *Config) error {
 	}
 }
 
+func WithSealer(i Sealer) Option {
+	return func(cfg *Config) error {
+		cfg.Sealer = i
+		return nil
+	}
+}
+
 func WithLibp2pAdditionalOptions(i ...libp2p.Option) func(cfg *Config) error {
 	return func(cfg *Config) error {
 		cfg.AdditionalOptions = append(cfg.Options, i...)

+ 3 - 2
pkg/vpn/dhcp.go

@@ -24,6 +24,7 @@ import (
 	"time"
 
 	"github.com/ipfs/go-log/v2"
+	"github.com/mudler/edgevpn/pkg/crypto"
 	"github.com/mudler/edgevpn/pkg/node"
 	"github.com/mudler/edgevpn/pkg/protocol"
 	"github.com/mudler/edgevpn/pkg/services"
@@ -36,7 +37,7 @@ import (
 func checkDHCPLease(c node.Config, leasedir string) string {
 	// retrieve lease if present
 
-	leaseFileName := utils.MD5(fmt.Sprintf("%s-ek", c.ExchangeKey))
+	leaseFileName := crypto.MD5(fmt.Sprintf("%s-ek", c.ExchangeKey))
 	leaseFile := filepath.Join(leasedir, leaseFileName)
 	if _, err := os.Stat(leaseFile); err == nil {
 		b, _ := ioutil.ReadFile(leaseFile)
@@ -114,7 +115,7 @@ func DHCP(l log.StandardLogger, announcetime time.Duration, leasedir string, add
 					}
 
 					// Save lease to disk
-					leaseFileName := utils.MD5(fmt.Sprintf("%s-ek", c.ExchangeKey))
+					leaseFileName := crypto.MD5(fmt.Sprintf("%s-ek", c.ExchangeKey))
 					leaseFile := filepath.Join(leasedir, leaseFileName)
 					l.Debugf("Writing lease to '%s'", leaseFile)
 					if err := ioutil.WriteFile(leaseFile, []byte(wantedIP), 0600); err != nil {