diff options
| author | Anton Tolchanov <anton@tailscale.com> | 2025-11-19 09:40:48 +0000 |
|---|---|---|
| committer | Anton Tolchanov <anton@tailscale.com> | 2026-03-31 13:04:57 +0100 |
| commit | 0b89e3173962c817e389d80ef5d18eadae8fe14f (patch) | |
| tree | 52bddb6bf6dc29090f3e97fa9e892769ecdc59e4 | |
| parent | 99f8039101036857f088c8b72cac365f80219a27 (diff) | |
| download | tailscale-knyar/nodekey.tar.xz tailscale-knyar/nodekey.zip | |
cmd/nodekey: add a tool to print nodekeyknyar/nodekey
| -rw-r--r-- | cmd/nodekey/nodekey.go | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/cmd/nodekey/nodekey.go b/cmd/nodekey/nodekey.go new file mode 100644 index 000000000..97ff6cbcf --- /dev/null +++ b/cmd/nodekey/nodekey.go @@ -0,0 +1,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 +} |
