diff --git a/cmd/sing-box/cmd_generate.go b/cmd/sing-box/cmd_generate.go new file mode 100644 index 00000000..fdadab77 --- /dev/null +++ b/cmd/sing-box/cmd_generate.go @@ -0,0 +1,139 @@ +package main + +import ( + "crypto/rand" + "encoding/base64" + "encoding/hex" + "os" + "strconv" + + "github.com/sagernet/sing-box/log" + + "github.com/gofrs/uuid" + "github.com/spf13/cobra" + "golang.zx2c4.com/wireguard/wgctrl/wgtypes" +) + +var commandGenerate = &cobra.Command{ + Use: "generate", + Short: "Generate things", +} + +func init() { + commandGenerate.AddCommand(commandGenerateUUID) + commandGenerate.AddCommand(commandGenerateRandom) + commandGenerate.AddCommand(commandGenerateWireGuardKeyPair) + commandGenerate.AddCommand(commandGenerateRealityKeyPair) + mainCommand.AddCommand(commandGenerate) +} + +var ( + outputBase64 bool + outputHex bool +) + +var commandGenerateRandom = &cobra.Command{ + Use: "rand ", + Short: "Generate random bytes", + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + err := generateRandom(args) + if err != nil { + log.Fatal(err) + } + }, +} + +func init() { + commandGenerateRandom.Flags().BoolVar(&outputBase64, "base64", false, "Generate base64 string") + commandGenerateRandom.Flags().BoolVar(&outputHex, "hex", false, "Generate hex string") +} + +func generateRandom(args []string) error { + length, err := strconv.Atoi(args[0]) + if err != nil { + return err + } + + randomBytes := make([]byte, length) + _, err = rand.Read(randomBytes) + if err != nil { + return err + } + + if outputBase64 { + _, err = os.Stdout.WriteString(base64.StdEncoding.EncodeToString(randomBytes) + "\n") + } else if outputHex { + _, err = os.Stdout.WriteString(hex.EncodeToString(randomBytes) + "\n") + } else { + _, err = os.Stdout.Write(randomBytes) + } + + return err +} + +var commandGenerateUUID = &cobra.Command{ + Use: "uuid", + Short: "Generate UUID string", + Args: cobra.NoArgs, + Run: func(cmd *cobra.Command, args []string) { + err := generateUUID() + if err != nil { + log.Fatal(err) + } + }, +} + +func generateUUID() error { + newUUID, err := uuid.NewV4() + if err != nil { + return err + } + _, err = os.Stdout.WriteString(newUUID.String() + "\n") + return err +} + +var commandGenerateWireGuardKeyPair = &cobra.Command{ + Use: "wg-keypair", + Short: "Generate WireGuard key pair", + Args: cobra.NoArgs, + Run: func(cmd *cobra.Command, args []string) { + err := generateWireGuardKey() + if err != nil { + log.Fatal(err) + } + }, +} + +func generateWireGuardKey() error { + privateKey, err := wgtypes.GeneratePrivateKey() + if err != nil { + return err + } + os.Stdout.WriteString("PrivateKey: " + privateKey.String() + "\n") + os.Stdout.WriteString("PublicKey: " + privateKey.PublicKey().String() + "\n") + return nil +} + +var commandGenerateRealityKeyPair = &cobra.Command{ + Use: "reality-keypair", + Short: "Generate reality key pair", + Args: cobra.NoArgs, + Run: func(cmd *cobra.Command, args []string) { + err := generateRealityKey() + if err != nil { + log.Fatal(err) + } + }, +} + +func generateRealityKey() error { + privateKey, err := wgtypes.GeneratePrivateKey() + if err != nil { + return err + } + publicKey := privateKey.PublicKey() + os.Stdout.WriteString("PrivateKey: " + base64.RawURLEncoding.EncodeToString(privateKey[:]) + "\n") + os.Stdout.WriteString("PublicKey: " + base64.RawURLEncoding.EncodeToString(publicKey[:]) + "\n") + return nil +} diff --git a/docs/configuration/inbound/shadowsocks.md b/docs/configuration/inbound/shadowsocks.md index f915e452..e69c9cb9 100644 --- a/docs/configuration/inbound/shadowsocks.md +++ b/docs/configuration/inbound/shadowsocks.md @@ -77,11 +77,11 @@ Both if empty. ==Required== -| Method | Password Format | -|---------------|-------------------------------------| -| none | / | -| 2022 methods | `openssl rand -base64 ` | -| other methods | any string | +| Method | Password Format | +|---------------|------------------------------------------------| +| none | / | +| 2022 methods | `sing-box generate rand --base64 ` | +| other methods | any string | ### Listen Fields diff --git a/docs/configuration/inbound/shadowsocks.zh.md b/docs/configuration/inbound/shadowsocks.zh.md index 1c26510c..11edd057 100644 --- a/docs/configuration/inbound/shadowsocks.zh.md +++ b/docs/configuration/inbound/shadowsocks.zh.md @@ -77,8 +77,8 @@ See [Listen Fields](/configuration/shared/listen) for details. ==必填== -| 方法 | 密码格式 | -|---------------|-------------------------------| -| none | / | -| 2022 methods | `openssl rand -base64 <密钥长度>` | -| other methods | 任意字符串 | \ No newline at end of file +| 方法 | 密码格式 | +|---------------|------------------------------------------| +| none | / | +| 2022 methods | `sing-box generate rand --base64 <密钥长度>` | +| other methods | 任意字符串 | \ No newline at end of file diff --git a/docs/configuration/shared/tls.md b/docs/configuration/shared/tls.md index 1cbab58e..00f50b13 100644 --- a/docs/configuration/shared/tls.md +++ b/docs/configuration/shared/tls.md @@ -319,7 +319,7 @@ Handshake server address and [Dial options](/configuration/shared/dial). ==Required== -Private key, generated by `./xray x25519`. +Private key, generated by `sing-box generate reality-keypair`. #### public_key @@ -327,7 +327,7 @@ Private key, generated by `./xray x25519`. ==Required== -Public key, generated by `./xray x25519`. +Public key, generated by `sing-box generate reality-keypair`. #### short_id diff --git a/docs/configuration/shared/tls.zh.md b/docs/configuration/shared/tls.zh.md index 4b974e2e..5f8c2721 100644 --- a/docs/configuration/shared/tls.zh.md +++ b/docs/configuration/shared/tls.zh.md @@ -315,7 +315,7 @@ MAC 密钥。 ==必填== -私钥,由 `./xray x25519` 生成。 +私钥,由 `sing-box generate reality-keypair` 生成。 #### public_key @@ -323,7 +323,7 @@ MAC 密钥。 ==必填== -公钥,由 `./xray x25519` 生成。 +公钥,由 `sing-box generate reality-keypair` 生成。 #### short_id diff --git a/go.mod b/go.mod index 38d9cfee..6fd3972f 100644 --- a/go.mod +++ b/go.mod @@ -47,6 +47,7 @@ require ( golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb golang.org/x/net v0.7.0 golang.org/x/sys v0.5.0 + golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230215201556-9c5414ab4bde google.golang.org/grpc v1.53.0 google.golang.org/protobuf v1.28.1 gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c diff --git a/go.sum b/go.sum index 624b276a..17dd6f20 100644 --- a/go.sum +++ b/go.sum @@ -266,6 +266,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230215201556-9c5414ab4bde h1:ybF7AMzIUikL9x4LgwEmzhXtzRpKNqngme1VGDWz+Nk= +golang.zx2c4.com/wireguard/wgctrl v0.0.0-20230215201556-9c5414ab4bde/go.mod h1:mQqgjkW8GQQcJQsbBvK890TKqUK1DfKWkuBGbOkuMHQ= google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w= google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM= google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc=