You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
142 lines
2.8 KiB
142 lines
2.8 KiB
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 |
|
}
|
|
|