wireguard.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. package wireguard
  2. import (
  3. "crypto/rand"
  4. "encoding/base64"
  5. "encoding/hex"
  6. "errors"
  7. "strings"
  8. "golang.org/x/crypto/curve25519"
  9. )
  10. // GenerateWireguardKeypair generates a base64 encoded private and public key pair for Wireguard.
  11. func GenerateWireguardKeypair() (privateKey string, publicKey string, err error) {
  12. var priv [32]byte
  13. if _, err := rand.Read(priv[:]); err != nil {
  14. return "", "", err
  15. }
  16. priv[0] &= 248
  17. priv[31] &= 127
  18. priv[31] |= 64
  19. var pub [32]byte
  20. curve25519.ScalarBaseMult(&pub, &priv)
  21. return base64.StdEncoding.EncodeToString(priv[:]), base64.StdEncoding.EncodeToString(pub[:]), nil
  22. }
  23. // GenerateWireguardPSK generates a base64 encoded 32-byte pre-shared key for Wireguard.
  24. func GenerateWireguardPSK() (string, error) {
  25. var psk [32]byte
  26. if _, err := rand.Read(psk[:]); err != nil {
  27. return "", err
  28. }
  29. return base64.StdEncoding.EncodeToString(psk[:]), nil
  30. }
  31. // PublicKeyFromPrivate derives the base64 public key for a base64 (or hex) Wireguard private key.
  32. func PublicKeyFromPrivate(privateKey string) (string, error) {
  33. priv, err := decodeWireguardKey(privateKey)
  34. if err != nil {
  35. return "", err
  36. }
  37. var pub [32]byte
  38. curve25519.ScalarBaseMult(&pub, &priv)
  39. return base64.StdEncoding.EncodeToString(pub[:]), nil
  40. }
  41. // KeyToHex converts a base64 (or already-hex) 32-byte Wireguard key into the
  42. // lowercase hex form xray-core's wireguard proxy expects: its ParseKey uses
  43. // hex.DecodeString, and the device IPC layer wants hex for public_key and
  44. // preshared_key. An empty input yields an empty result so optional keys pass
  45. // through untouched.
  46. func KeyToHex(key string) (string, error) {
  47. if key == "" {
  48. return "", nil
  49. }
  50. raw, err := decodeWireguardKey(key)
  51. if err != nil {
  52. return "", err
  53. }
  54. return hex.EncodeToString(raw[:]), nil
  55. }
  56. // decodeWireguardKey accepts a 64-char hex key or a base64 key (standard or
  57. // URL-safe alphabet, with or without padding) and returns the raw 32 bytes.
  58. func decodeWireguardKey(key string) ([32]byte, error) {
  59. var out [32]byte
  60. if key == "" {
  61. return out, errors.New("wireguard: empty key")
  62. }
  63. if len(key) == 64 {
  64. if raw, err := hex.DecodeString(key); err == nil {
  65. if len(raw) != 32 {
  66. return out, errors.New("wireguard: key must decode to 32 bytes")
  67. }
  68. copy(out[:], raw)
  69. return out, nil
  70. }
  71. }
  72. trimmed := strings.TrimRight(key, "=")
  73. var raw []byte
  74. var err error
  75. if strings.ContainsAny(trimmed, "+/") {
  76. raw, err = base64.RawStdEncoding.DecodeString(trimmed)
  77. } else {
  78. raw, err = base64.RawURLEncoding.DecodeString(trimmed)
  79. }
  80. if err != nil {
  81. return out, err
  82. }
  83. if len(raw) != 32 {
  84. return out, errors.New("wireguard: key must decode to 32 bytes")
  85. }
  86. copy(out[:], raw)
  87. return out, nil
  88. }