Documentation ¶
Index ¶
- Constants
- Variables
- func DecryptOnce(cipher *Cipher, salt []byte, plainText, cipherText []byte) ([]byte, error)
- func DecryptSeparateHeader(cipher *Cipher, dst, src []byte) error
- func MakeTestPayload(size int) []byte
- func MakeTestSecrets(n int) []string
- func Pack(dst, plaintext []byte, cipher *Cipher) ([]byte, error)
- func PackAesWithSeparateHeader(dst, plaintext []byte, cipher *Cipher, sessionAEAD cipher.AEAD) ([]byte, error)
- func ParseTCPReqHeader(r Reader, cipherConfig CipherConfig) (string, []byte, error)
- func ParseTCPRespHeader(r Reader, clientSalt []byte, cipherConfig CipherConfig) ([]byte, error)
- func ParseUDPHeader(plaintext []byte, htype byte, csid []byte, cipherConfig CipherConfig) (socksAddrStart int, socksAddr socks.Addr, payload []byte, err error)
- func SupportedCipherNames() []string
- func Unpack(dst, pkt []byte, cipher *Cipher) (plaintextStart int, plaintext []byte, err error)
- func UnpackAesWithSeparateHeader(dst, pkt, separateHeader []byte, unpackAEAD cipher.AEAD) ([]byte, error)
- func WriteClientUDPHeader(plaintext []byte, cipherConfig CipherConfig, sid []byte, pid uint64, ...) (n int, err error)
- func WritePadding(b []byte, paddingLen int) int
- func WriteRandomPadding(b []byte, targetPort int, max int) int
- func WriteTCPReqHeader(dst, socksaddr []byte, addPadding bool, cipherConfig CipherConfig) (n int)
- func WriteTCPRespHeader(dst, clientSalt []byte, cipherConfig CipherConfig) (n int)
- func WriteUDPHeader(plaintext []byte, htype byte, sid []byte, pid uint64, csid []byte, ...) (n int)
- type ChunkReader
- type Cipher
- type CipherConfig
- type DecryptionErr
- type Reader
- type SaltGenerator
- type Writer
Constants ¶
const ( HeaderTypeClientStream = 0 HeaderTypeServerStream = 1 HeaderTypeClientPacket = 0 HeaderTypeServerPacket = 1 MinPaddingLength = 0 MaxPaddingLength = 900 // type + 64-bit timestamp + socks address + padding length + padding TCPReqHeaderMaxLength = 1 + 8 + socks.MaxAddrLen + 2 + MaxPaddingLength // type + 64-bit timestamp + max salt length TCPRespHeaderMaxLength = 1 + 8 + 32 // server session id + packet id + type + timestamp + client session id + padding length UDPServerMessageHeaderFixedLength = 8 + 8 + 1 + 8 + 8 + 2 // client session id + packet id + type + timestamp + padding length UDPClientMessageHeaderFixedLength = 8 + 8 + 1 + 8 + 2 )
const TestCipher = "chacha20-ietf-poly1305"
TestCipher is a preferred cipher to use in testing.
Variables ¶
var ( ErrIncompleteHeaderInFirstChunk = errors.New("header in first chunk is missing or incomplete") ErrPaddingExceedChunkBorder = errors.New("padding in first chunk is shorter than advertised") ErrBadTimestamp = errors.New("time diff is over 30 seconds") ErrTypeMismatch = errors.New("header type mismatch") ErrPaddingLengthOutOfRange = errors.New("padding length is less than 0 or greater than 900") ErrClientSaltMismatch = errors.New("client salt in response header does not match request") ErrClientSessionIDMismatch = errors.New("client session ID in server message header does not match current session") ErrTooManyServerSessions = errors.New("server session changed more than once during the last minute") )
var ErrShortPacket = errors.New("short packet")
Functions ¶
func DecryptOnce ¶
DecryptOnce will decrypt the cipherText using the cipher and salt, appending the output to plainText.
func DecryptSeparateHeader ¶
func MakeTestPayload ¶
MakeTestPayload returns a slice of `size` arbitrary bytes.
func MakeTestSecrets ¶
MakeTestSecrets returns a slice of `n` test passwords. Not secure!
func Pack ¶
Pack encrypts a Shadowsocks-UDP packet and returns a slice containing the encrypted packet. dst must be big enough to hold the encrypted packet. If plaintext and dst overlap but are not aligned for in-place encryption, this function will panic.
func PackAesWithSeparateHeader ¶
func PackAesWithSeparateHeader(dst, plaintext []byte, cipher *Cipher, sessionAEAD cipher.AEAD) ([]byte, error)
Pack function for 2022-blake3-aes-256-gcm. Do not encrypt header before calling this function. This function encrypts the separate header after sealing AEAD.
plaintext should start with the separate header.
func ParseTCPReqHeader ¶
func ParseTCPReqHeader(r Reader, cipherConfig CipherConfig) (string, []byte, error)
ParseTCPReqHeader reads the first payload chunk, validates the header, and returns the target address, initial payload, or an error.
For Shadowsocks 2022, the first payload chunk MUST contain either a non-zero-length padding or initial payload, or both (not recommended client behavior but allowed). If the padding length is 0 and there's no initial payload, an error is returned.
func ParseTCPRespHeader ¶
func ParseTCPRespHeader(r Reader, clientSalt []byte, cipherConfig CipherConfig) ([]byte, error)
func ParseUDPHeader ¶
func ParseUDPHeader(plaintext []byte, htype byte, csid []byte, cipherConfig CipherConfig) (socksAddrStart int, socksAddr socks.Addr, payload []byte, err error)
For spec 2022, this function only parses the decrypted AEAD header. csid is the expected client session id, used when verifying a server packet.
func SupportedCipherNames ¶
func SupportedCipherNames() []string
SupportedCipherNames lists the names of the AEAD ciphers that are supported.
func Unpack ¶
Unpack decrypts a Shadowsocks UDP packet and returns the plaintext offset in the original packet buffer, a slice containing the decrypted plaintext (header + payload) or an error.
If dst is present, it is used to store the plaintext, and must have enough capacity. If dst is nil, decryption proceeds in-place.
func UnpackAesWithSeparateHeader ¶
func UnpackAesWithSeparateHeader(dst, pkt, separateHeader []byte, unpackAEAD cipher.AEAD) ([]byte, error)
Unpack function for 2022-blake3-aes-256-gcm. If separateHeader is nil, DecryptSeparateheader MUST be called to decrypte the separate header in-place before passing the ciphertext. The returned buffer includes the separate header.
func WriteClientUDPHeader ¶
func WriteClientUDPHeader(plaintext []byte, cipherConfig CipherConfig, sid []byte, pid uint64, targetAddr net.Addr, maxPacketSize int) (n int, err error)
WriteClientUDPHeader fills a Shadowsocks UDP header into the buffer.
For Shadowsocks 2022, make sure to increment packet ID upon returning.
No buffer length checks are performed. Make sure the buffer can hold the socks address.
func WritePadding ¶
func WriteTCPReqHeader ¶
func WriteTCPReqHeader(dst, socksaddr []byte, addPadding bool, cipherConfig CipherConfig) (n int)
func WriteTCPRespHeader ¶
func WriteTCPRespHeader(dst, clientSalt []byte, cipherConfig CipherConfig) (n int)
func WriteUDPHeader ¶
func WriteUDPHeader(plaintext []byte, htype byte, sid []byte, pid uint64, csid []byte, targetUDPAddr *net.UDPAddr, targetSocksAddr []byte, paddingLen int) (n int)
WriteUDPHeader fills a Shadowsocks 2022 UDP header into the buffer. Make sure to increment packet ID upon returning. To write a client header, pass csid as sid, and nil as csid. To write a server header, pass ssid as sid, and csid as csid. Pass either targetUDPAddr or targetSocksAddr.
For legacy Shadowsocks, call WriteUDPAddrToSocksAddr directly.
No buffer length checks are performed. Make sure the buffer can hold the socks address.
Types ¶
type ChunkReader ¶
type ChunkReader interface { // ReadChunk reads the next chunk and returns its payload. The caller must // complete its use of the returned buffer before the next call. // The buffer is nil iff there is an error. io.EOF indicates a close. ReadChunk() ([]byte, error) Salt() []byte }
ChunkReader is similar to io.Reader, except that it controls its own buffer granularity.
type Cipher ¶
type Cipher struct {
// contains filtered or unexported fields
}
Cipher encapsulates a Shadowsocks AEAD spec and a secret
func (*Cipher) Config ¶
func (c *Cipher) Config() CipherConfig
type CipherConfig ¶
type DecryptionErr ¶
type DecryptionErr struct {
Err error
}
func (*DecryptionErr) Error ¶
func (e *DecryptionErr) Error() string
func (*DecryptionErr) Unwrap ¶
func (e *DecryptionErr) Unwrap() error
type Reader ¶
type Reader interface { io.Reader io.WriterTo // Salt returns the salt used by this instance to derive the subkey. Salt() []byte // EnsureLeftover makes sure that the leftover slice is not nil. // If it's nil, a read is attempted and the result is returned. EnsureLeftover() error // LeftoverZeroCopy returns the leftover slice without copying. // The content of the returned slice won't change until next read. LeftoverZeroCopy() []byte }
Reader is an io.Reader that also implements io.WriterTo to allow for piping the data without extra allocations and copies.
type SaltGenerator ¶
SaltGenerator generates unique salts to use in Shadowsocks connections.
var ( // RandomSaltGenerator is a basic SaltGenerator. RandomSaltGenerator SaltGenerator = randomSaltGenerator{} // High performance random salt/nonce generator Blake3KeyedHashSaltGenerator = NewBlake3KeyedHashReader(24) )
func NewBlake3KeyedHashReader ¶
func NewBlake3KeyedHashReader(size int) SaltGenerator
type Writer ¶
type Writer struct {
// contains filtered or unexported fields
}
Writer is an io.Writer that also implements io.ReaderFrom to allow for piping the data without extra allocations and copies. The LazyWrite and Flush methods allow a header to be added but delayed until the first write, for concatenation. All methods except Flush must be called from a single thread.
func NewShadowsocksWriter ¶
func NewShadowsocksWriter(writer io.Writer, ssCipher *Cipher, saltGenerator SaltGenerator, lazyWriteBuf []byte, addPaddingOnFlush bool) (*Writer, error)
NewShadowsocksWriter creates a Writer that encrypts the given Writer using the shadowsocks protocol with the given shadowsocks cipher.
addPaddingOnFlush: true, lazyWriteBuf != nil: Shadowsocks 2022 client writer addPaddingOnFlush: false, lazyWriteBuf != nil: Shadowsocks 2022 server writer, Legacy Shadowsocks client writer addPaddingOnFlush: false, lazyWriteBuf == nil: Legacy Shadowsocks server writer