风扇滑翔翼 1 месяц назад
Родитель
Сommit
d100be5ad5
4 измененных файлов с 98 добавлено и 80 удалено
  1. 1 1
      go.mod
  2. 90 4
      main/commands/all/tls/ech.go
  3. 7 5
      transport/internet/tls/config.go
  4. 0 70
      transport/internet/tls/ech.go

+ 1 - 1
go.mod

@@ -1,6 +1,6 @@
 module github.com/xtls/xray-core
 
-go 1.25.7
+go 1.26
 
 require (
 	github.com/apernet/quic-go v0.57.2-0.20260111184307-eec823306178

+ 90 - 4
main/commands/all/tls/ech.go

@@ -1,11 +1,14 @@
 package tls
 
 import (
+	"crypto/ecdh"
+	"crypto/hpke"
+	"crypto/rand"
 	"encoding/base64"
 	"encoding/pem"
+	"io"
 	"os"
 
-	"github.com/xtls/reality/hpke"
 	"github.com/xtls/xray-core/common"
 	"github.com/xtls/xray-core/main/commands/base"
 	"github.com/xtls/xray-core/transport/internet/tls"
@@ -40,15 +43,15 @@ func executeECH(cmd *base.Command, args []string) {
 	// if *input_pqSignatureSchemesEnabled {
 	// 	kem = 0x30 // hpke.KEM_X25519_KYBER768_DRAFT00
 	// } else {
-	kem = hpke.DHKEM_X25519_HKDF_SHA256
+	kem = hpke.DHKEM(ecdh.X25519()).ID()
 	// }
 
-	echConfig, priv, err := tls.GenerateECHKeySet(0, *input_serverName, kem)
+	echConfig, priv, err := generateECHKeySet(0, *input_serverName, kem)
 	common.Must(err)
 
 	var configBuffer, keyBuffer []byte
 	if *input_echServerKeys == "" {
-		configBytes, _ := tls.MarshalBinary(echConfig)
+		configBytes, _ := marshalBinary(echConfig)
 		var b cryptobyte.Builder
 		b.AddUint16LengthPrefixed(func(child *cryptobyte.Builder) {
 			child.AddBytes(configBytes)
@@ -91,3 +94,86 @@ func executeECH(cmd *base.Command, args []string) {
 		os.Stdout.WriteString("ECH server keys: \n" + base64.StdEncoding.EncodeToString(keyBuffer) + "\n")
 	}
 }
+
+type EchConfig struct {
+	Version              uint16
+	ConfigID             uint8
+	KemID                uint16
+	PublicKey            []byte
+	SymmetricCipherSuite []EchCipher
+	MaxNameLength        uint8
+	PublicName           []byte
+	Extensions           []Extension
+}
+
+type EchCipher struct {
+	KDFID  uint16
+	AEADID uint16
+}
+
+type Extension struct {
+	Type uint16
+	Data []byte
+}
+
+// reference github.com/OmarTariq612/goech
+func marshalBinary(ech EchConfig) ([]byte, error) {
+	var b cryptobyte.Builder
+	b.AddUint16(ech.Version)
+	b.AddUint16LengthPrefixed(func(child *cryptobyte.Builder) {
+		child.AddUint8(ech.ConfigID)
+		child.AddUint16(ech.KemID)
+		child.AddUint16(uint16(len(ech.PublicKey)))
+		child.AddBytes(ech.PublicKey)
+		child.AddUint16LengthPrefixed(func(child *cryptobyte.Builder) {
+			for _, cipherSuite := range ech.SymmetricCipherSuite {
+				child.AddUint16(cipherSuite.KDFID)
+				child.AddUint16(cipherSuite.AEADID)
+			}
+		})
+		child.AddUint8(ech.MaxNameLength)
+		child.AddUint8(uint8(len(ech.PublicName)))
+		child.AddBytes(ech.PublicName)
+		child.AddUint16LengthPrefixed(func(child *cryptobyte.Builder) {
+			for _, extention := range ech.Extensions {
+				child.AddUint16(extention.Type)
+				child.AddBytes(extention.Data)
+			}
+		})
+	})
+	return b.Bytes()
+}
+
+const ExtensionEncryptedClientHello = 0xfe0d
+
+func generateECHKeySet(configID uint8, domain string, kem uint16) (EchConfig, []byte, error) {
+	config := EchConfig{
+		Version:    ExtensionEncryptedClientHello,
+		ConfigID:   configID,
+		PublicName: []byte(domain),
+		KemID:      kem,
+		SymmetricCipherSuite: []EchCipher{
+			{KDFID: hpke.HKDFSHA256().ID(), AEADID: hpke.AES128GCM().ID()},
+			{KDFID: hpke.HKDFSHA256().ID(), AEADID: hpke.AES256GCM().ID()},
+			{KDFID: hpke.HKDFSHA256().ID(), AEADID: hpke.ChaCha20Poly1305().ID()},
+			{KDFID: hpke.HKDFSHA384().ID(), AEADID: hpke.AES128GCM().ID()},
+			{KDFID: hpke.HKDFSHA384().ID(), AEADID: hpke.AES256GCM().ID()},
+			{KDFID: hpke.HKDFSHA384().ID(), AEADID: hpke.ChaCha20Poly1305().ID()},
+			{KDFID: hpke.HKDFSHA512().ID(), AEADID: hpke.AES128GCM().ID()},
+			{KDFID: hpke.HKDFSHA512().ID(), AEADID: hpke.AES256GCM().ID()},
+			{KDFID: hpke.HKDFSHA512().ID(), AEADID: hpke.ChaCha20Poly1305().ID()},
+		},
+		MaxNameLength: 0,
+		Extensions:    nil,
+	}
+	// if kem == hpke.DHKEM_X25519_HKDF_SHA256 {
+	curve := ecdh.X25519()
+	priv := make([]byte, 32)
+	_, err := io.ReadFull(rand.Reader, priv)
+	if err != nil {
+		return config, nil, err
+	}
+	privKey, _ := curve.NewPrivateKey(priv)
+	config.PublicKey = privKey.PublicKey().Bytes()
+	return config, priv, nil
+}

+ 7 - 5
transport/internet/tls/config.go

@@ -524,11 +524,13 @@ func ConfigFromStreamSettings(settings *internet.MemoryStreamConfig) *Config {
 
 func ParseCurveName(curveNames []string) []tls.CurveID {
 	curveMap := map[string]tls.CurveID{
-		"curvep256":      tls.CurveP256,
-		"curvep384":      tls.CurveP384,
-		"curvep521":      tls.CurveP521,
-		"x25519":         tls.X25519,
-		"x25519mlkem768": tls.X25519MLKEM768,
+		"curvep256":          tls.CurveP256,
+		"curvep384":          tls.CurveP384,
+		"curvep521":          tls.CurveP521,
+		"x25519":             tls.X25519,
+		"x25519mlkem768":     tls.X25519MLKEM768,
+		"secp256r1mlkem768":  tls.SecP256r1MLKEM768,
+		"secp384r1mlkem1024": tls.SecP384r1MLKEM1024,
 	}
 
 	var curveIDs []tls.CurveID

+ 0 - 70
transport/internet/tls/ech.go

@@ -3,8 +3,6 @@ package tls
 import (
 	"bytes"
 	"context"
-	"crypto/ecdh"
-	"crypto/rand"
 	"crypto/tls"
 	"encoding/base64"
 	"encoding/binary"
@@ -23,8 +21,6 @@ import (
 	"golang.org/x/net/http2"
 
 	"github.com/miekg/dns"
-	"github.com/xtls/reality"
-	"github.com/xtls/reality/hpke"
 	"github.com/xtls/xray-core/common/errors"
 	"github.com/xtls/xray-core/common/net"
 	"github.com/xtls/xray-core/common/utils"
@@ -330,34 +326,6 @@ func dnsQuery(server string, domain string, sockopt *internet.SocketConfig) ([]b
 	return nil, dns2.DefaultTTL, nil
 }
 
-// reference github.com/OmarTariq612/goech
-func MarshalBinary(ech reality.EchConfig) ([]byte, error) {
-	var b cryptobyte.Builder
-	b.AddUint16(ech.Version)
-	b.AddUint16LengthPrefixed(func(child *cryptobyte.Builder) {
-		child.AddUint8(ech.ConfigID)
-		child.AddUint16(ech.KemID)
-		child.AddUint16(uint16(len(ech.PublicKey)))
-		child.AddBytes(ech.PublicKey)
-		child.AddUint16LengthPrefixed(func(child *cryptobyte.Builder) {
-			for _, cipherSuite := range ech.SymmetricCipherSuite {
-				child.AddUint16(cipherSuite.KDFID)
-				child.AddUint16(cipherSuite.AEADID)
-			}
-		})
-		child.AddUint8(ech.MaxNameLength)
-		child.AddUint8(uint8(len(ech.PublicName)))
-		child.AddBytes(ech.PublicName)
-		child.AddUint16LengthPrefixed(func(child *cryptobyte.Builder) {
-			for _, extention := range ech.Extensions {
-				child.AddUint16(extention.Type)
-				child.AddBytes(extention.Data)
-			}
-		})
-	})
-	return b.Bytes()
-}
-
 var ErrInvalidLen = errors.New("goech: invalid length")
 
 func ConvertToGoECHKeys(data []byte) ([]tls.EncryptedClientHelloKey, error) {
@@ -392,41 +360,3 @@ func ConvertToGoECHKeys(data []byte) ([]tls.EncryptedClientHelloKey, error) {
 	}
 	return keys, nil
 }
-
-const ExtensionEncryptedClientHello = 0xfe0d
-const KDF_HKDF_SHA384 = 0x0002
-const KDF_HKDF_SHA512 = 0x0003
-
-func GenerateECHKeySet(configID uint8, domain string, kem uint16) (reality.EchConfig, []byte, error) {
-	config := reality.EchConfig{
-		Version:    ExtensionEncryptedClientHello,
-		ConfigID:   configID,
-		PublicName: []byte(domain),
-		KemID:      kem,
-		SymmetricCipherSuite: []reality.EchCipher{
-			{KDFID: hpke.KDF_HKDF_SHA256, AEADID: hpke.AEAD_AES_128_GCM},
-			{KDFID: hpke.KDF_HKDF_SHA256, AEADID: hpke.AEAD_AES_256_GCM},
-			{KDFID: hpke.KDF_HKDF_SHA256, AEADID: hpke.AEAD_ChaCha20Poly1305},
-			{KDFID: KDF_HKDF_SHA384, AEADID: hpke.AEAD_AES_128_GCM},
-			{KDFID: KDF_HKDF_SHA384, AEADID: hpke.AEAD_AES_256_GCM},
-			{KDFID: KDF_HKDF_SHA384, AEADID: hpke.AEAD_ChaCha20Poly1305},
-			{KDFID: KDF_HKDF_SHA512, AEADID: hpke.AEAD_AES_128_GCM},
-			{KDFID: KDF_HKDF_SHA512, AEADID: hpke.AEAD_AES_256_GCM},
-			{KDFID: KDF_HKDF_SHA512, AEADID: hpke.AEAD_ChaCha20Poly1305},
-		},
-		MaxNameLength: 0,
-		Extensions:    nil,
-	}
-	// if kem == hpke.DHKEM_X25519_HKDF_SHA256 {
-	curve := ecdh.X25519()
-	priv := make([]byte, 32) //x25519
-	_, err := io.ReadFull(rand.Reader, priv)
-	if err != nil {
-		return config, nil, err
-	}
-	privKey, _ := curve.NewPrivateKey(priv)
-	config.PublicKey = privKey.PublicKey().Bytes()
-	return config, priv, nil
-	// }
-	// TODO: add mlkem768 (former kyber768 draft00). The golang mlkem private key is 64 bytes seed?
-}