Add shadowsocks 2022 EIH support

This commit is contained in:
世界 2022-04-21 15:14:22 +08:00
parent 0b4282f72b
commit 603c62165e
No known key found for this signature in database
GPG key ID: CD109927C34A63C4
2 changed files with 133 additions and 31 deletions

View file

@ -167,13 +167,17 @@ func NewLocalClient(f *flags) (*LocalClient, error) {
if f.Method == shadowsocks.MethodNone { if f.Method == shadowsocks.MethodNone {
client.method = shadowsocks.NewNone() client.method = shadowsocks.NewNone()
} else { } else {
var key []byte var pskList [][]byte
if f.Key != "" { if f.Key != "" {
decoded, err := base64.StdEncoding.DecodeString(f.Key) keyStrList := strings.Split(f.Key, ":")
if err != nil { pskList = make([][]byte, len(keyStrList))
return nil, E.Cause(err, "decode key") for i, keyStr := range keyStrList {
key, err := base64.StdEncoding.DecodeString(keyStr)
if err != nil {
return nil, E.Cause(err, "decode key")
}
pskList[i] = key
} }
key = decoded
} }
var rng io.Reader var rng io.Reader
if f.UseSystemRNG { if f.UseSystemRNG {
@ -185,13 +189,16 @@ func NewLocalClient(f *flags) (*LocalClient, error) {
rng = &shadowsocks.ReducedEntropyReader{Reader: rng} rng = &shadowsocks.ReducedEntropyReader{Reader: rng}
} }
if common.Contains(shadowaead.List, f.Method) { if common.Contains(shadowaead.List, f.Method) {
method, err := shadowaead.New(f.Method, key, []byte(f.Password), rng, false) if len(pskList) > 1 {
return nil, shadowaead.ErrBadKey
}
method, err := shadowaead.New(f.Method, pskList[0], []byte(f.Password), rng, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
client.method = method client.method = method
} else if common.Contains(shadowaead_2022.List, f.Method) { } else if common.Contains(shadowaead_2022.List, f.Method) {
method, err := shadowaead_2022.New(f.Method, key, rng) method, err := shadowaead_2022.New(f.Method, pskList, rng)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -22,6 +22,7 @@ import (
"github.com/sagernet/sing/protocol/shadowsocks" "github.com/sagernet/sing/protocol/shadowsocks"
"github.com/sagernet/sing/protocol/shadowsocks/shadowaead" "github.com/sagernet/sing/protocol/shadowsocks/shadowaead"
"github.com/sagernet/sing/protocol/socks" "github.com/sagernet/sing/protocol/socks"
"golang.org/x/crypto/chacha20"
"golang.org/x/crypto/chacha20poly1305" "golang.org/x/crypto/chacha20poly1305"
wgReplay "golang.zx2c4.com/wireguard/replay" wgReplay "golang.zx2c4.com/wireguard/replay"
"lukechampine.com/blake3" "lukechampine.com/blake3"
@ -64,39 +65,57 @@ var List = []string{
"2022-blake3-chacha20-poly1305", "2022-blake3-chacha20-poly1305",
} }
func New(method string, psk []byte, secureRNG io.Reader) (shadowsocks.Method, error) { func New(method string, pskList [][]byte, secureRNG io.Reader) (shadowsocks.Method, error) {
m := &Method{ m := &Method{
name: method, name: method,
key: psk, psk: pskList[len(pskList)-1],
pskList: pskList,
secureRNG: secureRNG, secureRNG: secureRNG,
replayFilter: replay.NewCuckoo(60), replayFilter: replay.NewCuckoo(60),
} }
if len(psk) != KeySaltSize { for _, psk := range pskList {
return nil, shadowaead.ErrBadKey if len(psk) != KeySaltSize {
return nil, shadowaead.ErrBadKey
}
}
if len(pskList) > 1 {
pskHash := make([]byte, len(pskList)-1*aes.BlockSize)
for i, psk := range pskList {
if i == 0 {
continue
}
hash := blake3.Sum512(psk)
copy(pskHash[aes.BlockSize*(i-1):aes.BlockSize*i], hash[:aes.BlockSize])
}
m.pskHash = pskHash
} }
switch method { switch method {
case "2022-blake3-aes-128-gcm": case "2022-blake3-aes-128-gcm":
m.keyLength = 16 m.keyLength = 16
m.constructor = newAESGCM m.constructor = newAESGCM
m.udpBlockCipher = newAES(psk) m.blockConstructor = newAES
m.udpBlockCipher = newAES(m.psk)
case "2022-blake3-aes-256-gcm": case "2022-blake3-aes-256-gcm":
m.keyLength = 32 m.keyLength = 32
m.constructor = newAESGCM m.constructor = newAESGCM
m.udpBlockCipher = newAES(psk) m.blockConstructor = newAES
m.udpBlockCipher = newAES(m.psk)
case "2022-blake3-chacha20-poly1305": case "2022-blake3-chacha20-poly1305":
m.keyLength = 32 m.keyLength = 32
m.constructor = newChacha20Poly1305 m.constructor = newChacha20Poly1305
m.udpCipher = newXChacha20Poly1305(psk) m.streamConstructor = newChacha20
m.udpCipher = newXChacha20Poly1305(m.psk)
} }
return m, nil return m, nil
} }
func Blake3DeriveKey(secret, salt []byte, keyLength int) []byte { func Blake3DeriveKey(psk, salt []byte, keyLength int) []byte {
sessionKey := make([]byte, 2*KeySaltSize) sessionKey := make([]byte, 2*KeySaltSize)
copy(sessionKey, secret) copy(sessionKey, psk)
copy(sessionKey[len(secret):], salt) copy(sessionKey[KeySaltSize:], salt)
outKey := buf.Make(keyLength) outKey := buf.Make(keyLength)
blake3.DeriveKey(outKey, "shadowsocks 2022 session subkey", sessionKey) blake3.DeriveKey(outKey, "shadowsocks 2022 session subkey", sessionKey)
return outKey return outKey
@ -116,6 +135,12 @@ func newAESGCM(key []byte) cipher.AEAD {
return aead return aead
} }
func newChacha20(key []byte) cipher.Stream {
_nonce := make([]byte, chacha20.NonceSize)
stream, _ := chacha20.NewUnauthenticatedCipher(key, common.Dup(_nonce))
return stream
}
func newChacha20Poly1305(key []byte) cipher.AEAD { func newChacha20Poly1305(key []byte) cipher.AEAD {
cipher, err := chacha20poly1305.New(key) cipher, err := chacha20poly1305.New(key)
common.Must(err) common.Must(err)
@ -129,14 +154,18 @@ func newXChacha20Poly1305(key []byte) cipher.AEAD {
} }
type Method struct { type Method struct {
name string name string
keyLength int keyLength int
constructor func(key []byte) cipher.AEAD constructor func(key []byte) cipher.AEAD
udpCipher cipher.AEAD blockConstructor func(key []byte) cipher.Block
udpBlockCipher cipher.Block streamConstructor func(key []byte) cipher.Stream
key []byte udpCipher cipher.AEAD
secureRNG io.Reader udpBlockCipher cipher.Block
replayFilter replay.Filter psk []byte
pskList [][]byte
pskHash []byte
secureRNG io.Reader
replayFilter replay.Filter
} }
func (m *Method) Name() string { func (m *Method) Name() string {
@ -147,6 +176,30 @@ func (m *Method) KeyLength() int {
return m.keyLength return m.keyLength
} }
func (m *Method) WriteExtendedIdentityHeaders(request *buf.Buffer, salt []byte) {
pskLen := len(m.pskList)
if pskLen < 2 {
return
}
for i, psk := range m.pskList {
keyMaterial := make([]byte, 2*KeySaltSize)
copy(keyMaterial, psk)
copy(keyMaterial[KeySaltSize:], salt)
_identitySubkey := buf.Make(m.keyLength)
identitySubkey := common.Dup(_identitySubkey)
blake3.DeriveKey(identitySubkey, "shadowsocks 2022 identity subkey", keyMaterial)
pskHash := m.pskHash[aes.BlockSize*i : aes.BlockSize*(i+1)]
if m.blockConstructor != nil {
m.blockConstructor(identitySubkey).Encrypt(request.Extend(16), pskHash)
} else {
m.streamConstructor(identitySubkey).XORKeyStream(request.Extend(16), pskHash)
}
if i == pskLen-2 {
break
}
}
}
func (m *Method) DialConn(conn net.Conn, destination *M.AddrPort) (net.Conn, error) { func (m *Method) DialConn(conn net.Conn, destination *M.AddrPort) (net.Conn, error) {
shadowsocksConn := &clientConn{ shadowsocksConn := &clientConn{
Conn: conn, Conn: conn,
@ -190,15 +243,18 @@ func (c *clientConn) writeRequest(payload []byte) error {
salt := make([]byte, KeySaltSize) salt := make([]byte, KeySaltSize)
common.Must1(io.ReadFull(c.method.secureRNG, salt)) common.Must1(io.ReadFull(c.method.secureRNG, salt))
common.Must1(request.Write(salt)) common.Must1(request.Write(salt))
c.method.WriteExtendedIdentityHeaders(request, salt)
var writer io.Writer = c.Conn var writer io.Writer = c.Conn
writer = &buf.BufferedWriter{ writer = &buf.BufferedWriter{
Writer: writer, Writer: writer,
Buffer: request, Buffer: request,
} }
key := Blake3DeriveKey(c.method.psk, salt, c.method.keyLength)
writer = shadowaead.NewWriter( writer = shadowaead.NewWriter(
writer, writer,
c.method.constructor(Blake3DeriveKey(c.method.key, salt, c.method.keyLength)), c.method.constructor(common.Dup(key)),
MaxPacketSize, MaxPacketSize,
) )
@ -271,9 +327,10 @@ func (c *clientConn) readResponse() error {
return E.New("salt not unique") return E.New("salt not unique")
} }
key := Blake3DeriveKey(c.method.psk, salt, c.method.keyLength)
reader := shadowaead.NewReader( reader := shadowaead.NewReader(
c.Conn, c.Conn,
c.method.constructor(Blake3DeriveKey(c.method.key, salt, c.method.keyLength)), c.method.constructor(common.Dup(key)),
MaxPacketSize, MaxPacketSize,
) )
@ -361,12 +418,48 @@ type clientPacketConn struct {
func (c *clientPacketConn) WritePacket(buffer *buf.Buffer, destination *M.AddrPort) error { func (c *clientPacketConn) WritePacket(buffer *buf.Buffer, destination *M.AddrPort) error {
defer buffer.Release() defer buffer.Release()
header := buf.New() header := buf.New()
pskLen := len(c.method.pskList)
var dataIndex int
if c.method.udpCipher != nil { if c.method.udpCipher != nil {
common.Must1(header.ReadFullFrom(c.method.secureRNG, PacketNonceSize)) common.Must1(header.ReadFullFrom(c.method.secureRNG, PacketNonceSize))
if pskLen > 1 {
for i, psk := range c.method.pskList {
pskHash := c.method.pskHash[aes.BlockSize*i : aes.BlockSize*(i+1)]
identityHeader := header.Extend(aes.BlockSize)
for textI := 0; textI < aes.BlockSize; textI++ {
identityHeader[textI] = pskHash[textI] ^ header.Byte(textI)
}
c.method.streamConstructor(psk).XORKeyStream(identityHeader, identityHeader)
if i == pskLen-2 {
break
}
}
}
dataIndex = buffer.Len()
} else {
dataIndex = aes.BlockSize
} }
common.Must( common.Must(
binary.Write(header, binary.BigEndian, c.session.sessionId), binary.Write(header, binary.BigEndian, c.session.sessionId),
binary.Write(header, binary.BigEndian, c.session.nextPacketId()), binary.Write(header, binary.BigEndian, c.session.nextPacketId()),
)
if c.method.udpCipher == nil && pskLen > 1 {
for i, psk := range c.method.pskList {
dataIndex += aes.BlockSize
pskHash := c.method.pskHash[aes.BlockSize*i : aes.BlockSize*(i+1)]
identityHeader := header.Extend(aes.BlockSize)
for textI := 0; textI < aes.BlockSize; textI++ {
identityHeader[textI] = pskHash[textI] ^ header.Byte(textI)
}
c.method.blockConstructor(psk).Encrypt(identityHeader, identityHeader)
if i == pskLen-2 {
break
}
}
}
common.Must(
header.WriteByte(HeaderTypeClient), header.WriteByte(HeaderTypeClient),
binary.Write(header, binary.BigEndian, uint64(time.Now().Unix())), binary.Write(header, binary.BigEndian, uint64(time.Now().Unix())),
binary.Write(header, binary.BigEndian, uint16(0)), // padding length binary.Write(header, binary.BigEndian, uint16(0)), // padding length
@ -377,11 +470,11 @@ func (c *clientPacketConn) WritePacket(buffer *buf.Buffer, destination *M.AddrPo
} }
buffer = buffer.WriteBufferAtFirst(header) buffer = buffer.WriteBufferAtFirst(header)
if c.method.udpCipher != nil { if c.method.udpCipher != nil {
c.method.udpCipher.Seal(buffer.Index(PacketNonceSize), buffer.To(PacketNonceSize), buffer.From(PacketNonceSize), nil) c.method.udpCipher.Seal(buffer.Index(dataIndex), buffer.To(dataIndex), buffer.From(dataIndex), nil)
buffer.Extend(c.method.udpCipher.Overhead()) buffer.Extend(c.method.udpCipher.Overhead())
} else { } else {
packetHeader := buffer.To(aes.BlockSize) packetHeader := buffer.To(aes.BlockSize)
c.session.cipher.Seal(buffer.Index(aes.BlockSize), packetHeader[4:16], buffer.From(aes.BlockSize), nil) c.session.cipher.Seal(buffer.Index(dataIndex), packetHeader[4:16], buffer.From(dataIndex), nil)
buffer.Extend(c.session.cipher.Overhead()) buffer.Extend(c.session.cipher.Overhead())
c.method.udpBlockCipher.Encrypt(packetHeader, packetHeader) c.method.udpBlockCipher.Encrypt(packetHeader, packetHeader)
} }
@ -424,7 +517,8 @@ func (c *clientPacketConn) ReadPacket(buffer *buf.Buffer) (*M.AddrPort, error) {
} else if sessionId == c.session.lastRemoteSessionId { } else if sessionId == c.session.lastRemoteSessionId {
remoteCipher = c.session.lastRemoteCipher remoteCipher = c.session.lastRemoteCipher
} else { } else {
remoteCipher = c.method.constructor(Blake3DeriveKey(c.method.key, packetHeader[:8], c.method.keyLength)) key := Blake3DeriveKey(c.method.psk, packetHeader[:8], c.method.keyLength)
remoteCipher = c.method.constructor(common.Dup(key))
} }
_, err = remoteCipher.Open(buffer.Index(0), packetHeader[4:16], buffer.Bytes(), nil) _, err = remoteCipher.Open(buffer.Index(0), packetHeader[4:16], buffer.Bytes(), nil)
if err != nil { if err != nil {
@ -522,7 +616,8 @@ func (m *Method) newUDPSession() *udpSession {
if m.udpCipher == nil { if m.udpCipher == nil {
sessionId := make([]byte, 8) sessionId := make([]byte, 8)
binary.BigEndian.PutUint64(sessionId, session.sessionId) binary.BigEndian.PutUint64(sessionId, session.sessionId)
session.cipher = m.constructor(Blake3DeriveKey(m.key, sessionId, m.keyLength)) key := Blake3DeriveKey(m.psk, sessionId, m.keyLength)
session.cipher = m.constructor(common.Dup(key))
} }
return session return session
} }