summaryrefslogtreecommitdiffhomepage
path: root/cmd/nodekey/nodekey.go
blob: 97ff6cbcf1ffb0005035a4954da5f8814b40b89c (plain)
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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
package main

import (
	"fmt"
	"log"
	"os"

	"go4.org/mem"
	"tailscale.com/types/key"
)

func main() {
	for _, arg := range os.Args[1:] {
		k, err := key.ParseNodePublicUntyped(mem.B([]byte(arg)))
		if err != nil {
			log.Printf("invalid node key %q: %v", arg, err)
		}
		b, err := parseDebug32(arg)
		if err != nil {
			log.Printf("invalid debug32 format for %q: %v", arg, err)
		}
		k = key.NodePublicFromRaw32(mem.B(b[:]))
		log.Printf("node key: %s", k.ShortString())
		log.Printf("node key: %s", k.String())
	}
}

// parseDebug32 attempts to reconstruct the first 4 bytes of a key
// from the Tailscale debug representation like "[abcde]".
// The remaining bytes will be zero.
func parseDebug32(s string) ([32]byte, error) {
	var k [32]byte

	if s == "" {
		return k, nil
	}
	if len(s) != 7 || s[0] != '[' || s[6] != ']' {
		return k, fmt.Errorf("invalid debug32 format %q", s)
	}

	decode64 := func(c byte) (byte, bool) {
		switch {
		case 'A' <= c && c <= 'Z':
			return c - 'A', true
		case 'a' <= c && c <= 'z':
			return c - 'a' + 26, true
		case '0' <= c && c <= '9':
			return c - '0' + 52, true
		case c == '+':
			return 62, true
		case c == '/':
			return 63, true
		default:
			return 0, false
		}
	}

	v0, ok := decode64(s[1])
	if !ok {
		return k, fmt.Errorf("invalid debug32 format %q", s)
	}
	v1, ok := decode64(s[2])
	if !ok {
		return k, fmt.Errorf("invalid debug32 format %q", s)
	}
	v2, ok := decode64(s[3])
	if !ok {
		return k, fmt.Errorf("invalid debug32 format %q", s)
	}
	v3, ok := decode64(s[4])
	if !ok {
		return k, fmt.Errorf("invalid debug32 format %q", s)
	}
	v4, ok := decode64(s[5])
	if !ok {
		return k, fmt.Errorf("invalid debug32 format %q", s)
	}

	k[0] = v0<<2 | v1>>4
	k[1] = v1<<4 | v2>>2
	k[2] = v2<<6 | v3
	k[3] = v4 << 2 // low 2 bits were discarded by debug32

	return k, nil
}