mirror of
https://github.com/tailscale/tailscale.git
synced 2024-12-01 22:15:51 +00:00
922d9546bf
It was one of the top garbage producers on my phone. It's slated to be deleted and replaced anyway, but this helps in the meantime. The go.sum changes look scary, but the new dep only adds 240 bytes to the binary. The go.sum noise is just cmd/go being aggressive in including a lot of stuff (which is being fixed in Go 1.15, for what I understand). And I ran a go mod tidy, which added some too. (I had to write a custom wrapper around go mod tidy because this mod tidy normally breaks on tailscale.io/control being missing but referenced in tests) Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
103 lines
2.8 KiB
Go
103 lines
2.8 KiB
Go
// Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// Package key defines some types related to curve25519 keys.
|
|
package key
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"go4.org/mem"
|
|
"golang.org/x/crypto/curve25519"
|
|
)
|
|
|
|
// Private represents a curve25519 private key.
|
|
type Private [32]byte
|
|
|
|
// Private reports whether p is the zero value.
|
|
func (p Private) IsZero() bool { return p == Private{} }
|
|
|
|
// B32 returns k as the *[32]byte type that's used by the
|
|
// golang.org/x/crypto packages. This allocates; it might
|
|
// not be appropriate for performance-sensitive paths.
|
|
func (k Private) B32() *[32]byte { return (*[32]byte)(&k) }
|
|
|
|
// Public represents a curve25519 public key.
|
|
type Public [32]byte
|
|
|
|
// Public reports whether p is the zero value.
|
|
func (p Public) IsZero() bool { return p == Public{} }
|
|
|
|
// ShortString returns the Tailscale conventional debug representation
|
|
// of a public key: the first five base64 digits of the key, in square
|
|
// brackets.
|
|
func (p Public) ShortString() string {
|
|
return "[" + base64.StdEncoding.EncodeToString(p[:])[:5] + "]"
|
|
}
|
|
|
|
func (p Public) MarshalText() ([]byte, error) {
|
|
buf := make([]byte, base64.StdEncoding.EncodedLen(len(p)))
|
|
base64.StdEncoding.Encode(buf, p[:])
|
|
return buf, nil
|
|
}
|
|
|
|
func (p *Public) UnmarshalText(txt []byte) error {
|
|
if *p != (Public{}) {
|
|
return errors.New("refusing to unmarshal into non-zero key.Public")
|
|
}
|
|
n, err := base64.StdEncoding.Decode(p[:], txt)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if n != 32 {
|
|
return fmt.Errorf("short decode of %d; want 32", n)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// B32 returns k as the *[32]byte type that's used by the
|
|
// golang.org/x/crypto packages. This allocates; it might
|
|
// not be appropriate for performance-sensitive paths.
|
|
func (k Public) B32() *[32]byte { return (*[32]byte)(&k) }
|
|
|
|
func (k Private) Public() Public {
|
|
var pub [32]byte
|
|
curve25519.ScalarBaseMult(&pub, (*[32]byte)(&k))
|
|
return Public(pub)
|
|
}
|
|
|
|
// NewPublicFromHexMem parses a public key in its hex form, given in m.
|
|
// The provided m must be exactly 64 bytes in length.
|
|
func NewPublicFromHexMem(m mem.RO) (Public, error) {
|
|
if m.Len() != 64 {
|
|
return Public{}, errors.New("invalid length")
|
|
}
|
|
var p Public
|
|
for i := range p {
|
|
a, ok1 := fromHexChar(m.At(i*2 + 0))
|
|
b, ok2 := fromHexChar(m.At(i*2 + 1))
|
|
if !ok1 || !ok2 {
|
|
return Public{}, errors.New("invalid hex character")
|
|
}
|
|
p[i] = (a << 4) | b
|
|
}
|
|
return p, nil
|
|
}
|
|
|
|
// fromHexChar converts a hex character into its value and a success flag.
|
|
func fromHexChar(c byte) (byte, bool) {
|
|
switch {
|
|
case '0' <= c && c <= '9':
|
|
return c - '0', true
|
|
case 'a' <= c && c <= 'f':
|
|
return c - 'a' + 10, true
|
|
case 'A' <= c && c <= 'F':
|
|
return c - 'A' + 10, true
|
|
}
|
|
|
|
return 0, false
|
|
}
|