|
|
|
package wireguard
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"crypto/rand"
|
|
|
|
"encoding/base64"
|
|
|
|
"errors"
|
|
|
|
|
|
|
|
"golang.org/x/crypto/curve25519"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
// PrivateKeySize is the length in bytes of a Wireguard Private Key
|
|
|
|
PrivateKeySize = 32
|
|
|
|
// PublicKeySize is the length in bytes of a Wireguard Public Key
|
|
|
|
PublicKeySize = 32
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
// ErrInvalidKeySize indicates the key size is wrong
|
|
|
|
ErrInvalidKeySize = errors.New("invalid key size")
|
|
|
|
)
|
|
|
|
|
|
|
|
type (
|
|
|
|
// PrivateKey is a binary Wireguard Private Key
|
|
|
|
PrivateKey []byte
|
|
|
|
// PublicKey is a binary Wireguard Public Key
|
|
|
|
PublicKey []byte
|
|
|
|
)
|
|
|
|
|
|
|
|
func (key PrivateKey) String() string {
|
|
|
|
return encodeKey(key)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (pub PublicKey) String() string {
|
|
|
|
return encodeKey(pub)
|
|
|
|
}
|
|
|
|
|
|
|
|
// IsZero tells if the key hasn't been set
|
|
|
|
func (key PrivateKey) IsZero() bool {
|
|
|
|
return len(key) == 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// IsZero tells if the key hasn't been set
|
|
|
|
func (pub PublicKey) IsZero() bool {
|
|
|
|
return len(pub) == 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// Equal checks if two private keys are identical
|
|
|
|
func (key PrivateKey) Equal(alter PrivateKey) bool {
|
|
|
|
return bytes.Equal(key, alter)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Equal checks if two public keys are identical
|
|
|
|
func (pub PublicKey) Equal(alter PublicKey) bool {
|
|
|
|
return bytes.Equal(pub, alter)
|
|
|
|
}
|
|
|
|
|
|
|
|
// PrivateKeyFromBase64 decodes a base64-based string into
|
|
|
|
// a [PrivateKey]
|
|
|
|
func PrivateKeyFromBase64(data string) (PrivateKey, error) {
|
|
|
|
b, err := decodeKey(data, PrivateKeySize)
|
|
|
|
return b, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// PublicKeyFromBase64 decodes a base64-based string into
|
|
|
|
// a [PublicKey]
|
|
|
|
func PublicKeyFromBase64(data string) (PublicKey, error) {
|
|
|
|
b, err := decodeKey(data, PublicKeySize)
|
|
|
|
return b, err
|
|
|
|
}
|
|
|
|
|
|
|
|
func encodeKey(b []byte) string {
|
|
|
|
switch {
|
|
|
|
case len(b) == 0:
|
|
|
|
return ""
|
|
|
|
default:
|
|
|
|
return base64.StdEncoding.EncodeToString(b)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func decodeKey(data string, size int) ([]byte, error) {
|
|
|
|
b, err := base64.StdEncoding.DecodeString(data)
|
|
|
|
switch {
|
|
|
|
case err != nil:
|
|
|
|
return []byte{}, err
|
|
|
|
case len(b) != size:
|
|
|
|
err = ErrInvalidKeySize
|
|
|
|
return []byte{}, err
|
|
|
|
default:
|
|
|
|
return b, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewPrivateKey creates a new PrivateKey
|
|
|
|
func NewPrivateKey() (PrivateKey, error) {
|
|
|
|
var s [PrivateKeySize]byte
|
|
|
|
|
|
|
|
_, err := rand.Read(s[:])
|
|
|
|
if err != nil {
|
|
|
|
return []byte{}, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// apply same clamping as wireguard-go/device/noise-helpers.go
|
|
|
|
s[0] &= 0xf8
|
|
|
|
s[31] = (s[31] & 0x7f) | 0x40
|
|
|
|
|
|
|
|
return s[:], nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Public generates the corresponding PublicKey
|
|
|
|
func (key PrivateKey) Public() PublicKey {
|
|
|
|
if len(key) != PrivateKeySize {
|
|
|
|
return []byte{}
|
|
|
|
}
|
|
|
|
|
|
|
|
out := [PublicKeySize]byte{}
|
|
|
|
in := (*[PrivateKeySize]byte)(key)
|
|
|
|
|
|
|
|
curve25519.ScalarBaseMult(&out, in)
|
|
|
|
return out[:]
|
|
|
|
}
|
|
|
|
|
|
|
|
// KeyPair holds a Key pair
|
|
|
|
type KeyPair struct {
|
|
|
|
PrivateKey PrivateKey
|
|
|
|
PublicKey PublicKey
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewKeyPair creates a new KeyPair for Wireguard
|
|
|
|
func NewKeyPair() (*KeyPair, error) {
|
|
|
|
key, err := NewPrivateKey()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
out := &KeyPair{
|
|
|
|
PrivateKey: key,
|
|
|
|
PublicKey: key.Public(),
|
|
|
|
}
|
|
|
|
return out, nil
|
|
|
|
}
|