1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
// Package oaddr provides onion address formatting
package oaddr
import (
"crypto"
"crypto/ed25519"
"encoding/base32"
"fmt"
"strings"
bed25519 "github.com/cretz/bine/torutil/ed25519"
"golang.org/x/crypto/sha3"
)
// OnionAddress is an Ed25519 public key that represents a v3 onion address
type OnionAddress [ed25519.PublicKeySize]byte
// New outputs an onion address from a public key as defined in RFC 8032
func New(pub []byte) (addr OnionAddress, err error) {
if got, want := len(pub), ed25519.PublicKeySize; got != want {
return addr, fmt.Errorf("invalid public key size: %d", got)
}
copy(addr[:], pub)
return addr, nil
}
// NewFromSigner outputs an onion address for a given signer
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)
}
return
}
// String formats addr as defined in rend-spec-v3, see:
// https://gitweb.torproject.org/torspec.git/tree/rend-spec-v3.txt#n2160
func (addr OnionAddress) String() string {
b := addr[:]
b = append(b, addr.checksum()...)
b = append(b, addr.version()...)
return strings.ToLower(base32.StdEncoding.EncodeToString(b)) + ".onion"
}
func (addr OnionAddress) checksum() []byte {
h := sha3.New256()
h.Write([]byte(".onion checksum"))
h.Write(addr[:])
h.Write(addr.version())
sum := h.Sum(nil)
return sum[:2]
}
func (addr OnionAddress) version() []byte {
return []byte{0x03}
}
|