commit 4476e4b3a62aa25d375bd1fde5a1087aff54d77c
parent e2de1893f1c13c07b2394820fd224e1f58655a0f
Author: parazyd <parazyd@dyne.org>
Date: Wed, 13 Dec 2017 00:57:35 +0100
Implement ed25519 functionality.
This will come handy later on when Tor v3 hidden services are supported
in ControlPort spec.
Diffstat:
2 files changed, 110 insertions(+), 0 deletions(-)
diff --git a/README.md b/README.md
@@ -18,6 +18,8 @@ go get -u github.com/parazyd/tor-dam/...
#### Go
```
+golang.org/x/crypto/ed25519
+golang.org/x/crypto/sha3
golang.org/x/net/proxy
github.com/go-redis/redis
```
diff --git a/pkg/damlib/crypto_25519.go b/pkg/damlib/crypto_25519.go
@@ -0,0 +1,108 @@
+package damlib
+
+// See LICENSE file for copyright and license details.
+
+import (
+ "crypto/rand"
+ "encoding/base32"
+ "io/ioutil"
+ "log"
+ "strings"
+
+ "golang.org/x/crypto/ed25519"
+ "golang.org/x/crypto/sha3"
+)
+
+// GenEd25519 generates an ed25519 keypair. Returns error on failure.
+func GenEd25519() (ed25519.PublicKey, ed25519.PrivateKey, error) {
+ log.Println("Generating ed25519 keypair...")
+ rng := rand.Reader
+ pk, sk, err := ed25519.GenerateKey(rng)
+ if err != nil {
+ return nil, nil, err
+ }
+ return pk, sk, nil
+}
+
+// SavePubEd25519 writes a ed25519.PublicKey type to a given string filename.
+// Returns error upon failure.
+func SavePubEd25519(filename string, key ed25519.PublicKey) error {
+ log.Println("Writing ed25519 public key to", filename)
+ const pkprefix = "== ed25519v1-public: type0 =="
+ var pub []byte
+ for _, i := range []byte(pkprefix) {
+ pub = append(pub, i)
+ }
+ for _, i := range []byte(key) {
+ pub = append(pub, i)
+ }
+ if err := ioutil.WriteFile(filename, pub, 0600); err != nil {
+ return err
+ }
+ return nil
+}
+
+// SavePrivEd25519 writes a ed25519.PrivateKey type to a given string filename.
+// Returns error upon failure.
+func SavePrivEd25519(filename string, key ed25519.PrivateKey) error {
+ log.Println("Writing ed25519 private key to", filename)
+ const skprefix = "== ed25519v1-secret: type0 =="
+ var sec []byte
+ for _, i := range []byte(skprefix) {
+ sec = append(sec, i)
+ }
+ for _, i := range []byte(key) {
+ sec = append(sec, i)
+ }
+ if err := ioutil.WriteFile(filename, sec, 0600); err != nil {
+ return err
+ }
+ return nil
+}
+
+// OnionFromPubkeyEd25519 generates a valid onion address from a given ed25519
+// public key. Returns the onion address as a slice of bytes.
+//
+// Tor Spec excerpt from https://gitweb.torproject.org/torspec.git/tree/rend-spec-v3.txt
+// ---
+// 6. Encoding onion addresses [ONIONADDRESS]
+// The onion address of a hidden service includes its identity public key, a
+// version field and a basic checksum. All this information is then base32
+// encoded as shown below:
+//
+// onion_address = base32(PUBKEY | CHECKSUM | VERSION) + ".onion"
+// CHECKSUM = H(".onion checksum" | PUBKEY | VERSION)[:2]
+//
+// where:
+// - PUBKEY is the 32 bytes ed25519 master pubkey of the hidden service.
+// - VERSION is an one byte version field (default value '\x03')
+// - ".onion checksum" is a constant string
+// - CHECKSUM is truncated to two bytes before inserting it in onion_address
+func OnionFromPubkeyEd25519(pubkey ed25519.PublicKey) []byte {
+ const hashConst = ".onion checksum"
+ const versConst = '\x03'
+
+ var h []byte
+ for _, i := range []byte(hashConst) {
+ h = append(h, i)
+ }
+ for _, i := range []byte(pubkey) {
+ h = append(h, i)
+ }
+ h = append(h, byte(versConst))
+
+ csum := sha3.Sum256(h)
+ checksum := csum[:2]
+
+ var enc []byte
+ for _, i := range []byte(pubkey) {
+ enc = append(enc, i)
+ }
+ for _, i := range checksum {
+ enc = append(enc, i)
+ }
+ enc = append(enc, byte(versConst))
+
+ encoded := base32.StdEncoding.EncodeToString(enc)
+ return []byte(strings.ToLower(encoded) + ".onion")
+}