mirror of
https://github.com/SagerNet/sing-box.git
synced 2025-07-24 06:54:08 +08:00
82 lines
2.4 KiB
Go
82 lines
2.4 KiB
Go
package tls
|
|
|
|
import (
|
|
"crypto/ecdh"
|
|
"crypto/rand"
|
|
"encoding/pem"
|
|
|
|
"golang.org/x/crypto/cryptobyte"
|
|
)
|
|
|
|
type ECHCapableConfig interface {
|
|
Config
|
|
ECHConfigList() []byte
|
|
SetECHConfigList([]byte)
|
|
}
|
|
|
|
func ECHKeygenDefault(publicName string) (configPem string, keyPem string, err error) {
|
|
echKey, err := ecdh.X25519().GenerateKey(rand.Reader)
|
|
if err != nil {
|
|
return
|
|
}
|
|
echConfig, err := marshalECHConfig(0, echKey.PublicKey().Bytes(), publicName, 0)
|
|
if err != nil {
|
|
return
|
|
}
|
|
configBuilder := cryptobyte.NewBuilder(nil)
|
|
configBuilder.AddUint16LengthPrefixed(func(builder *cryptobyte.Builder) {
|
|
builder.AddBytes(echConfig)
|
|
})
|
|
configBytes, err := configBuilder.Bytes()
|
|
if err != nil {
|
|
return
|
|
}
|
|
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: configBytes}))
|
|
keyPem = string(pem.EncodeToMemory(&pem.Block{Type: "ECH KEYS", Bytes: keyBytes}))
|
|
return
|
|
}
|
|
|
|
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)
|
|
}
|
|
})
|
|
builder.AddUint8(maxNameLen)
|
|
builder.AddUint8LengthPrefixed(func(builder *cryptobyte.Builder) {
|
|
builder.AddBytes([]byte(publicName))
|
|
})
|
|
builder.AddUint16(0) // extensions
|
|
})
|
|
return builder.Bytes()
|
|
}
|