1
0
Эх сурвалжийг харах

Remove dependency on circl

世界 2 сар өмнө
parent
commit
0f2035149c
3 өөрчлөгдсөн 57 нэмэгдсэн , 140 устгасан
  1. 57 137
      common/tls/ech_shared.go
  2. 0 1
      go.mod
  3. 0 2
      go.sum

+ 57 - 137
common/tls/ech_shared.go

@@ -1,14 +1,11 @@
 package tls
 
 import (
-	"bytes"
-	"encoding/binary"
+	"crypto/ecdh"
+	"crypto/rand"
 	"encoding/pem"
 
-	E "github.com/sagernet/sing/common/exceptions"
-
-	"github.com/cloudflare/circl/hpke"
-	"github.com/cloudflare/circl/kem"
+	"golang.org/x/crypto/cryptobyte"
 )
 
 type ECHCapableConfig interface {
@@ -17,145 +14,68 @@ type ECHCapableConfig interface {
 	SetECHConfigList([]byte)
 }
 
-func ECHKeygenDefault(serverName string) (configPem string, keyPem string, err error) {
-	cipherSuites := []echCipherSuite{
-		{
-			kdf:  hpke.KDF_HKDF_SHA256,
-			aead: hpke.AEAD_AES128GCM,
-		}, {
-			kdf:  hpke.KDF_HKDF_SHA256,
-			aead: hpke.AEAD_ChaCha20Poly1305,
-		},
-	}
-	keyConfig := []myECHKeyConfig{
-		{id: 0, kem: hpke.KEM_X25519_HKDF_SHA256},
-	}
-
-	keyPairs, err := echKeygen(0xfe0d, serverName, keyConfig, cipherSuites)
+func ECHKeygenDefault(publicName string) (configPem string, keyPem string, err error) {
+	echKey, err := ecdh.X25519().GenerateKey(rand.Reader)
 	if err != nil {
 		return
 	}
-
-	var configBuffer bytes.Buffer
-	var totalLen uint16
-	for _, keyPair := range keyPairs {
-		totalLen += uint16(len(keyPair.rawConf))
+	echConfig, err := marshalECHConfig(0, echKey.PublicKey().Bytes(), publicName, 0)
+	if err != nil {
+		return
 	}
-	binary.Write(&configBuffer, binary.BigEndian, totalLen)
-	for _, keyPair := range keyPairs {
-		configBuffer.Write(keyPair.rawConf)
+	configBuilder := cryptobyte.NewBuilder(nil)
+	configBuilder.AddUint16LengthPrefixed(func(builder *cryptobyte.Builder) {
+		builder.AddBytes(echConfig)
+	})
+	configBytes, err := configBuilder.Bytes()
+	if err != nil {
+		return
 	}
-
-	var keyBuffer bytes.Buffer
-	for _, keyPair := range keyPairs {
-		keyBuffer.Write(keyPair.rawKey)
+	keyBuilder := cryptobyte.NewBuilder(nil)
+	keyBuilder.AddUint16LengthPrefixed(func(builder *cryptobyte.Builder) {
+		builder.AddBytes(echKey.Bytes())
+	})
+	keyBuilder.AddUint16LengthPrefixed(func(builder *cryptobyte.Builder) {
+		builder.AddBytes(echConfig)
+	})
+	keyBytes, err := keyBuilder.Bytes()
+	if err != nil {
+		return
 	}
-
-	configPem = string(pem.EncodeToMemory(&pem.Block{Type: "ECH CONFIGS", Bytes: configBuffer.Bytes()}))
-	keyPem = string(pem.EncodeToMemory(&pem.Block{Type: "ECH KEYS", Bytes: keyBuffer.Bytes()}))
+	configPem = string(pem.EncodeToMemory(&pem.Block{Type: "ECH CONFIGS", Bytes: configBytes}))
+	keyPem = string(pem.EncodeToMemory(&pem.Block{Type: "ECH KEYS", Bytes: keyBytes}))
 	return
 }
 
-type echKeyConfigPair struct {
-	id      uint8
-	rawKey  []byte
-	conf    myECHKeyConfig
-	rawConf []byte
-}
-
-type echCipherSuite struct {
-	kdf  hpke.KDF
-	aead hpke.AEAD
-}
-
-type myECHKeyConfig struct {
-	id   uint8
-	kem  hpke.KEM
-	seed []byte
-}
-
-func echKeygen(version uint16, serverName string, conf []myECHKeyConfig, suite []echCipherSuite) ([]echKeyConfigPair, error) {
-	be := binary.BigEndian
-	// prepare for future update
-	if version != 0xfe0d {
-		return nil, E.New("unsupported ECH version", version)
-	}
-
-	suiteBuf := make([]byte, 0, len(suite)*4+2)
-	suiteBuf = be.AppendUint16(suiteBuf, uint16(len(suite))*4)
-	for _, s := range suite {
-		if !s.kdf.IsValid() || !s.aead.IsValid() {
-			return nil, E.New("invalid HPKE cipher suite")
-		}
-		suiteBuf = be.AppendUint16(suiteBuf, uint16(s.kdf))
-		suiteBuf = be.AppendUint16(suiteBuf, uint16(s.aead))
-	}
-
-	pairs := []echKeyConfigPair{}
-	for _, c := range conf {
-		pair := echKeyConfigPair{}
-		pair.id = c.id
-		pair.conf = c
-
-		if !c.kem.IsValid() {
-			return nil, E.New("invalid HPKE KEM")
-		}
-
-		kpGenerator := c.kem.Scheme().GenerateKeyPair
-		if len(c.seed) > 0 {
-			kpGenerator = func() (kem.PublicKey, kem.PrivateKey, error) {
-				pub, sec := c.kem.Scheme().DeriveKeyPair(c.seed)
-				return pub, sec, nil
+func marshalECHConfig(id uint8, pubKey []byte, publicName string, maxNameLen uint8) ([]byte, error) {
+	const extensionEncryptedClientHello = 0xfe0d
+	const DHKEM_X25519_HKDF_SHA256 = 0x0020
+	const KDF_HKDF_SHA256 = 0x0001
+	builder := cryptobyte.NewBuilder(nil)
+	builder.AddUint16(extensionEncryptedClientHello)
+	builder.AddUint16LengthPrefixed(func(builder *cryptobyte.Builder) {
+		builder.AddUint8(id)
+
+		builder.AddUint16(DHKEM_X25519_HKDF_SHA256) // The only DHKEM we support
+		builder.AddUint16LengthPrefixed(func(builder *cryptobyte.Builder) {
+			builder.AddBytes(pubKey)
+		})
+		builder.AddUint16LengthPrefixed(func(builder *cryptobyte.Builder) {
+			const (
+				AEAD_AES_128_GCM      = 0x0001
+				AEAD_AES_256_GCM      = 0x0002
+				AEAD_ChaCha20Poly1305 = 0x0003
+			)
+			for _, aeadID := range []uint16{AEAD_AES_128_GCM, AEAD_AES_256_GCM, AEAD_ChaCha20Poly1305} {
+				builder.AddUint16(KDF_HKDF_SHA256) // The only KDF we support
+				builder.AddUint16(aeadID)
 			}
-			if len(c.seed) < c.kem.Scheme().PrivateKeySize() {
-				return nil, E.New("HPKE KEM seed too short")
-			}
-		}
-
-		pub, sec, err := kpGenerator()
-		if err != nil {
-			return nil, E.Cause(err, "generate ECH config key pair")
-		}
-		b := []byte{}
-		b = be.AppendUint16(b, version)
-		b = be.AppendUint16(b, 0) // length field
-		// contents
-		// key config
-		b = append(b, c.id)
-		b = be.AppendUint16(b, uint16(c.kem))
-		pubBuf, err := pub.MarshalBinary()
-		if err != nil {
-			return nil, E.Cause(err, "serialize ECH public key")
-		}
-		b = be.AppendUint16(b, uint16(len(pubBuf)))
-		b = append(b, pubBuf...)
-
-		b = append(b, suiteBuf...)
-		// end key config
-		// max name len, not supported
-		b = append(b, 0)
-		// server name
-		b = append(b, byte(len(serverName)))
-		b = append(b, []byte(serverName)...)
-		// extensions, not supported
-		b = be.AppendUint16(b, 0)
-
-		be.PutUint16(b[2:], uint16(len(b)-4))
-
-		pair.rawConf = b
-
-		secBuf, err := sec.MarshalBinary()
-		if err != nil {
-			return nil, E.Cause(err, "serialize ECH private key")
-		}
-		sk := []byte{}
-		sk = be.AppendUint16(sk, uint16(len(secBuf)))
-		sk = append(sk, secBuf...)
-		sk = be.AppendUint16(sk, uint16(len(b)))
-		sk = append(sk, b...)
-		pair.rawKey = sk
-
-		pairs = append(pairs, pair)
-	}
-	return pairs, nil
+		})
+		builder.AddUint8(maxNameLen)
+		builder.AddUint8LengthPrefixed(func(builder *cryptobyte.Builder) {
+			builder.AddBytes([]byte(publicName))
+		})
+		builder.AddUint16(0) // extensions
+	})
+	return builder.Bytes()
 }

+ 0 - 1
go.mod

@@ -5,7 +5,6 @@ go 1.23.1
 require (
 	github.com/anytls/sing-anytls v0.0.8
 	github.com/caddyserver/certmagic v0.23.0
-	github.com/cloudflare/circl v1.6.1
 	github.com/coder/websocket v1.8.13
 	github.com/cretz/bine v0.2.0
 	github.com/go-chi/chi/v5 v5.2.2

+ 0 - 2
go.sum

@@ -20,8 +20,6 @@ github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK3
 github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
 github.com/cilium/ebpf v0.15.0 h1:7NxJhNiBT3NG8pZJ3c+yfrVdHY8ScgKD27sScgjLMMk=
 github.com/cilium/ebpf v0.15.0/go.mod h1:DHp1WyrLeiBh19Cf/tfiSMhqheEiK8fXFZ4No0P1Hso=
-github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0=
-github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
 github.com/coder/websocket v1.8.13 h1:f3QZdXy7uGVz+4uCJy2nTZyM0yTBj8yANEHhqlXZ9FE=
 github.com/coder/websocket v1.8.13/go.mod h1:LNVeNrXQZfe5qhS9ALED3uA+l5pPqvwXg3CKoDBB2gs=
 github.com/coreos/go-iptables v0.7.1-0.20240112124308-65c67c9f46e6 h1:8h5+bWd7R6AYUslN6c6iuZWTKsKxUFDlpnmilO6R2n0=