Переглянути джерело

models/key: Montogomery/Edwards Key

Signed-off-by: John Sahhar <[email protected]>
John Sahhar 3 роки тому
батько
коміт
34b839bcb2
4 змінених файлів з 114 додано та 0 видалено
  1. 1 0
      go.mod
  2. 2 0
      go.sum
  3. 75 0
      models/key.go
  4. 36 0
      models/key_test.go

+ 1 - 0
go.mod

@@ -39,6 +39,7 @@ require (
 
 require (
 	cloud.google.com/go v0.34.0 // indirect
+	filippo.io/edwards25519 v1.0.0-rc.1 // indirect
 	github.com/Microsoft/go-winio v0.4.14 // indirect
 	github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
 	github.com/davecgh/go-spew v1.1.1 // indirect

+ 2 - 0
go.sum

@@ -1,6 +1,8 @@
 cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
 cloud.google.com/go v0.34.0 h1:eOI3/cP2VTU6uZLDYAoic+eyzzB9YyGmJ7eIjl8rOPg=
 cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU=
+filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU=
 github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=

+ 75 - 0
models/key.go

@@ -0,0 +1,75 @@
+package models
+
+import (
+	"crypto/ed25519"
+	"crypto/rand"
+	"encoding/base64"
+	"errors"
+	"os"
+
+	"filippo.io/edwards25519"
+	"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
+)
+
+type (
+	Key struct {
+		point *edwards25519.Point
+	}
+)
+
+// Generates a new key.
+func NewKey() (*Key, error) {
+	seed := make([]byte, 64)
+	rand.Reader.Read(seed)
+	s, err := (&edwards25519.Scalar{}).SetUniformBytes(seed)
+	if err != nil {
+		return nil, err
+	}
+	return &Key{(&edwards25519.Point{}).ScalarBaseMult(s)}, nil
+}
+
+// Returns the private key in Edwards form used for EdDSA.
+func (n *Key) Ed25519PrivateKey() (ed25519.PrivateKey, error) {
+	if n.point == nil {
+		return ed25519.PrivateKey{}, errors.New("nil point")
+	}
+	if len(n.point.Bytes()) != ed25519.SeedSize {
+		return ed25519.PrivateKey{}, errors.New("incorrect seed size")
+	}
+	return ed25519.NewKeyFromSeed(n.point.Bytes()), nil
+}
+
+// Returns the private key in Montogomery form used for ECDH.
+func (n *Key) Curve25519PrivateKey() (wgtypes.Key, error) {
+	if n.point == nil {
+		return wgtypes.Key{}, errors.New("nil point")
+	}
+	if len(n.point.Bytes()) != ed25519.SeedSize {
+		return wgtypes.Key{}, errors.New("incorrect seed size")
+	}
+	return wgtypes.ParseKey(base64.StdEncoding.EncodeToString(n.point.BytesMontgomery()))
+}
+
+// Saves the private key to path.
+func (n *Key) Save(path string) error {
+	f, err := os.Create(path)
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+	f.Write(n.point.Bytes())
+	return nil
+}
+
+// Reads the private key from path.
+func ReadFrom(path string) (*Key, error) {
+	key, err := os.ReadFile(path)
+	if err != nil {
+		return nil, err
+	}
+	point, err := (&edwards25519.Point{}).SetBytes(key)
+	if err != nil {
+		return nil, err
+	}
+	return &Key{point}, nil
+}

+ 36 - 0
models/key_test.go

@@ -0,0 +1,36 @@
+package models
+
+import (
+	"os"
+	"testing"
+)
+
+func TestKey_Save(t *testing.T) {
+	testKeyPath := "test.key"
+	testKey, err := NewKey()
+	if err != nil {
+		t.Fatal(err)
+	}
+	tests := []struct {
+		name    string
+		key     *Key
+		wantErr bool
+	}{
+		{
+			"save-load",
+			testKey,
+			false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if err := tt.key.Save(testKeyPath); (err != nil) != tt.wantErr {
+				t.Errorf("Key.Save() error = %v, wantErr %v", err, tt.wantErr)
+			}
+			defer os.Remove(testKeyPath)
+			if _, err := ReadFrom(testKeyPath); err != nil {
+				t.Errorf("ReadFrom(%s) failed for newly saved key with err: %s", testKeyPath, err)
+			}
+		})
+	}
+}