Release 3X-UI for Docker / build (push) Canceled after 0s
Release 3X-UI / build (386) (push) Canceled after 0s
Release 3X-UI / build (amd64) (push) Canceled after 0s
Release 3X-UI / build (arm64) (push) Canceled after 0s
Release 3X-UI / build (armv5) (push) Canceled after 0s
Release 3X-UI / build (armv6) (push) Canceled after 0s
Release 3X-UI / build (armv7) (push) Canceled after 0s
Release 3X-UI / build (s390x) (push) Canceled after 0s
Release 3X-UI / Build for Windows (amd64) (push) Canceled after 0s
Release 3X-UI / Publish rolling dev release (push) Canceled after 0s
100 lines
2.6 KiB
Go
100 lines
2.6 KiB
Go
package wireguard
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"encoding/base64"
|
|
"encoding/hex"
|
|
"errors"
|
|
"strings"
|
|
|
|
"golang.org/x/crypto/curve25519"
|
|
)
|
|
|
|
// GenerateWireguardKeypair generates a base64 encoded private and public key pair for Wireguard.
|
|
func GenerateWireguardKeypair() (privateKey string, publicKey string, err error) {
|
|
var priv [32]byte
|
|
if _, err := rand.Read(priv[:]); err != nil {
|
|
return "", "", err
|
|
}
|
|
priv[0] &= 248
|
|
priv[31] &= 127
|
|
priv[31] |= 64
|
|
|
|
var pub [32]byte
|
|
curve25519.ScalarBaseMult(&pub, &priv)
|
|
|
|
return base64.StdEncoding.EncodeToString(priv[:]), base64.StdEncoding.EncodeToString(pub[:]), nil
|
|
}
|
|
|
|
// GenerateWireguardPSK generates a base64 encoded 32-byte pre-shared key for Wireguard.
|
|
func GenerateWireguardPSK() (string, error) {
|
|
var psk [32]byte
|
|
if _, err := rand.Read(psk[:]); err != nil {
|
|
return "", err
|
|
}
|
|
return base64.StdEncoding.EncodeToString(psk[:]), nil
|
|
}
|
|
|
|
// PublicKeyFromPrivate derives the base64 public key for a base64 (or hex) Wireguard private key.
|
|
func PublicKeyFromPrivate(privateKey string) (string, error) {
|
|
priv, err := decodeWireguardKey(privateKey)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
var pub [32]byte
|
|
curve25519.ScalarBaseMult(&pub, &priv)
|
|
return base64.StdEncoding.EncodeToString(pub[:]), nil
|
|
}
|
|
|
|
// KeyToHex converts a base64 (or already-hex) 32-byte Wireguard key into the
|
|
// lowercase hex form xray-core's wireguard proxy expects: its ParseKey uses
|
|
// hex.DecodeString, and the device IPC layer wants hex for public_key and
|
|
// preshared_key. An empty input yields an empty result so optional keys pass
|
|
// through untouched.
|
|
func KeyToHex(key string) (string, error) {
|
|
if key == "" {
|
|
return "", nil
|
|
}
|
|
raw, err := decodeWireguardKey(key)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return hex.EncodeToString(raw[:]), nil
|
|
}
|
|
|
|
// decodeWireguardKey accepts a 64-char hex key or a base64 key (standard or
|
|
// URL-safe alphabet, with or without padding) and returns the raw 32 bytes.
|
|
func decodeWireguardKey(key string) ([32]byte, error) {
|
|
var out [32]byte
|
|
if key == "" {
|
|
return out, errors.New("wireguard: empty key")
|
|
}
|
|
|
|
if len(key) == 64 {
|
|
if raw, err := hex.DecodeString(key); err == nil {
|
|
if len(raw) != 32 {
|
|
return out, errors.New("wireguard: key must decode to 32 bytes")
|
|
}
|
|
copy(out[:], raw)
|
|
return out, nil
|
|
}
|
|
}
|
|
|
|
trimmed := strings.TrimRight(key, "=")
|
|
var raw []byte
|
|
var err error
|
|
if strings.ContainsAny(trimmed, "+/") {
|
|
raw, err = base64.RawStdEncoding.DecodeString(trimmed)
|
|
} else {
|
|
raw, err = base64.RawURLEncoding.DecodeString(trimmed)
|
|
}
|
|
if err != nil {
|
|
return out, err
|
|
}
|
|
if len(raw) != 32 {
|
|
return out, errors.New("wireguard: key must decode to 32 bytes")
|
|
}
|
|
copy(out[:], raw)
|
|
return out, nil
|
|
}
|