aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRasmus Dahlberg <rasmus@rgdd.se>2022-10-13 17:47:14 +0200
committerRasmus Dahlberg <rasmus@rgdd.se>2022-10-13 18:04:49 +0200
commit2933ba510c7ac41e39b54667e3cb5f11fdea929d (patch)
tree84008607ffdf624ed0a39d7b25f8ea45b3d2c93f
parentda885286d66203715367f3e3d834268f10e09c97 (diff)
Add hs_ed25519_secret_key_parsing
-rw-r--r--go.mod1
-rw-r--r--go.sum17
-rw-r--r--pkg/oaddr/oaddr.go3
-rw-r--r--pkg/oaddr/oaddr_test.go2
-rw-r--r--pkg/okey/okey.go29
-rw-r--r--pkg/okey/okey_test.go51
-rw-r--r--pkg/okey/testonly/hostname1
-rw-r--r--pkg/okey/testonly/hs_ed25519_public_keybin0 -> 64 bytes
-rw-r--r--pkg/okey/testonly/hs_ed25519_secret_keybin0 -> 96 bytes
9 files changed, 104 insertions, 0 deletions
diff --git a/go.mod b/go.mod
index 0f70188..a140424 100644
--- a/go.mod
+++ b/go.mod
@@ -3,6 +3,7 @@ module sauteed-onions.org/onion-csr
go 1.18
require (
+ github.com/cretz/bine v0.2.0 // indirect
golang.org/x/crypto v0.0.0-20221010152910-d6f0a8c073c2 // indirect
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 // indirect
)
diff --git a/go.sum b/go.sum
index 762518a..ace54f0 100644
--- a/go.sum
+++ b/go.sum
@@ -1,4 +1,21 @@
+github.com/cretz/bine v0.2.0 h1:8GiDRGlTgz+o8H9DSnsl+5MeBK4HsExxgl6WgzOCuZo=
+github.com/cretz/bine v0.2.0/go.mod h1:WU4o9QR9wWp8AVKtTM1XD5vUHkEqnf2vVSo6dBqbetI=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/crypto v0.0.0-20221010152910-d6f0a8c073c2 h1:x8vtB3zMecnlqZIwJNUUpwYKYSqCz5jXbiyv0ZJJZeI=
golang.org/x/crypto v0.0.0-20221010152910-d6f0a8c073c2/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/pkg/oaddr/oaddr.go b/pkg/oaddr/oaddr.go
index f065ec9..fd8b6a4 100644
--- a/pkg/oaddr/oaddr.go
+++ b/pkg/oaddr/oaddr.go
@@ -8,6 +8,7 @@ import (
"fmt"
"strings"
+ bed25519 "github.com/cretz/bine/torutil/ed25519"
"golang.org/x/crypto/sha3"
)
@@ -29,6 +30,8 @@ func NewFromSigner(s crypto.Signer) (addr OnionAddress, err error) {
switch t := s.Public().(type) {
case ed25519.PublicKey:
addr, err = New(s.Public().(ed25519.PublicKey))
+ case bed25519.PublicKey:
+ addr, err = New(s.Public().(bed25519.PublicKey))
default:
err = fmt.Errorf("unknown key type: %v", t)
}
diff --git a/pkg/oaddr/oaddr_test.go b/pkg/oaddr/oaddr_test.go
index a37d4de..549bd67 100644
--- a/pkg/oaddr/oaddr_test.go
+++ b/pkg/oaddr/oaddr_test.go
@@ -5,6 +5,7 @@ import (
"crypto/ed25519"
"testing"
+ bed25519 "github.com/cretz/bine/torutil/ed25519"
"sauteed-onions.org/onion-csr/internal/testonly"
)
@@ -45,6 +46,7 @@ func TestNewFromSigner(t *testing.T) {
}{
{"rsa key", testonly.RSAPriv(t), OnionAddress{}},
{"valid", testonly.Ed25519Priv(t, testPriv), newAddr(t, testPub)},
+ {"valid", bed25519.FromCryptoPrivateKey(testonly.Ed25519Priv(t, testPriv)).PrivateKey(), newAddr(t, testPub)},
} {
addr, err := NewFromSigner(table.priv)
if got, want := err != nil, table.desc != "valid"; got != want {
diff --git a/pkg/okey/okey.go b/pkg/okey/okey.go
new file mode 100644
index 0000000..aba4f3e
--- /dev/null
+++ b/pkg/okey/okey.go
@@ -0,0 +1,29 @@
+// Package okey provides access to onion service private keys
+package okey
+
+import (
+ "crypto"
+ "fmt"
+ "os"
+
+ bed25519 "github.com/cretz/bine/torutil/ed25519"
+)
+
+// New parses the content of Tor's hs_ed25519_secret_key file by interpretting
+// bytes 32..96 as the 64-byte expanded seed. For reference, see:
+// https://gitlab.torproject.org/tpo/core/tor/-/blob/main/src/feature/keymgt/loadkey.c#L379
+func New(b []byte) (crypto.Signer, error) {
+ if len(b) != 96 {
+ return nil, fmt.Errorf("invalid key file size: %d", len(b))
+ }
+ return bed25519.PrivateKey(b[32:96]), nil
+}
+
+// NewFromHSDir reads and parses the hs_ed25519_secret_key file in a given directory
+func NewFromHSDir(dir string) (crypto.Signer, error) {
+ b, err := os.ReadFile(dir + "/hs_ed25519_secret_key")
+ if err != nil {
+ return nil, err
+ }
+ return New(b)
+}
diff --git a/pkg/okey/okey_test.go b/pkg/okey/okey_test.go
new file mode 100644
index 0000000..2636bb4
--- /dev/null
+++ b/pkg/okey/okey_test.go
@@ -0,0 +1,51 @@
+package okey
+
+import (
+ "bytes"
+ "os"
+ "testing"
+
+ bed25519 "github.com/cretz/bine/torutil/ed25519"
+)
+
+func TestNewFromHSDir(t *testing.T) {
+ if _, err := NewFromHSDir("no-such-directory"); err == nil {
+ t.Errorf("succeeded to read non-existing directory")
+ }
+
+ want := bed25519.PublicKey(hsPubFromFile(t, "testonly"))
+ if s, err := NewFromHSDir("testonly"); err != nil {
+ t.Errorf("failed reading valid directory: %v", err)
+ } else if got, ok := s.Public().(bed25519.PublicKey); !ok {
+ t.Errorf("wrong key type: %T", s.Public())
+ } else if !bytes.Equal(got, want) {
+ t.Errorf("got public key\n%x\nbut wanted\n%x", got, want)
+ }
+}
+
+func TestNew(t *testing.T) {
+ for _, table := range []struct {
+ desc string
+ priv []byte
+ want bed25519.PublicKey
+ }{
+ {"invalid: key size", make([]byte, 95), nil},
+ } {
+ _, err := New(table.priv)
+ if got, want := err != nil, table.desc != "valid"; got != want {
+ t.Errorf("%s: got error %v but wanted %v: %v", table.desc, got, want, err)
+ }
+ }
+}
+
+func hsPubFromFile(t *testing.T, dir string) []byte {
+ t.Helper()
+ b, err := os.ReadFile(dir + "/hs_ed25519_public_key")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(b) != 64 {
+ t.Fatalf("invalid public key file size: %d", len(b))
+ }
+ return b[32:64]
+}
diff --git a/pkg/okey/testonly/hostname b/pkg/okey/testonly/hostname
new file mode 100644
index 0000000..ed58ba6
--- /dev/null
+++ b/pkg/okey/testonly/hostname
@@ -0,0 +1 @@
+a3xo2fquvmhntjo663f4255bpskuuop4qru66xuzcmwfdl4fgiwt3uid.onion
diff --git a/pkg/okey/testonly/hs_ed25519_public_key b/pkg/okey/testonly/hs_ed25519_public_key
new file mode 100644
index 0000000..0a7493d
--- /dev/null
+++ b/pkg/okey/testonly/hs_ed25519_public_key
Binary files differ
diff --git a/pkg/okey/testonly/hs_ed25519_secret_key b/pkg/okey/testonly/hs_ed25519_secret_key
new file mode 100644
index 0000000..9ba4008
--- /dev/null
+++ b/pkg/okey/testonly/hs_ed25519_secret_key
Binary files differ