Super Fast
Bleeding edge techniques using Asynchronous I/O and Event-driven programming.
From 423723795ca1e2f0e914ec0328641083bd990ac1 Mon Sep 17 00:00:00 2001
From: madeye 404 First of all, upgrade your Linux kernel to 3.5 or later. To handle thousands of concurrent TCP connections, we should increase the limit of file descriptors opened. Edit the Add these two lines First of all, upgrade your Linux kernel to 3.5 or later. To handle thousands of concurrent TCP connections, we should increase the limit of file descriptors opened. Edit the Add these two lines AEAD stands for Authenticated Encryption with Associated Data. AEAD ciphers simultaneously provide confidentiality, integrity, and authenticity. They have excellent performance and power efficiency on modern hardware. Users should use AEAD ciphers whenever possible. The following AEAD ciphers are recommended. Compliant Shadowsocks implementations must support AEAD_CHACHA20_POLY1305. Implementations for devices with hardware AES acceleration should also implement AEAD_AES_128_GCM and AEAD_AES_256_GCM. Please refer to IANA AEAD registry for naming scheme and specification. The way Shadowsocks using AEAD ciphers is specified in SIP004 and amended in SIP007. SIP004 was proposed by @Mygod with design inspirations from @wongsyrone, @Noisyfox and @breakwa11. SIP007 was proposed by @riobard with input from @madeye, @Mygod, @wongsyrone, and many others. The master key can be input directly from user or generated from a password. The key derivation is still following EVP_BytesToKey(3) in OpenSSL. The detailed spec can be found here HKDF_SHA1 is a function that takes a secret key, a non-secret salt, an info string, and produces a subkey that is cryptographically strong even if the input secret key is weak. The info string binds the generated subkey to a specific application context. In our case, it must be the string "ss-subkey" without quotes. We derive a per-session subkey from a pre-shared master key using HKDF_SHA1. Salt must be unique through the entire life of the pre-shared master key. AE_encrypt is a function that takes a secret key, a non-secret nonce, a message, and produces ciphertext and authentication tag. Nonce must be unique for a given key in each invocation. AE_decrypt is a function that takes a secret key, non-secret nonce, ciphertext, authentication tag, and produces original message. If any of the input is tampered with, decryption will fail. An AEAD encrypted TCP stream starts with a randomly generated salt to derive the per-session subkey, followed by any number of encrypted chunks. Each chunk has the following structure: Payload length is a 2-byte big-endian unsigned integer capped at 0x3FFF. The higher two bits are reserved and must be set to zero. Payload is therefore limited to 16*1024 - 1 bytes. The first AEAD encrypt/decrypt operation uses a counting nonce starting from 0. After each encrypt/decrypt operation, the nonce is incremented by one as if it were an unsigned little-endian integer. Note that each TCP chunk involves two AEAD encrypt/decrypt operation: one for the payload length, and one for the payload. Therefore each chunk increases the nonce twice. An AEAD encrypted UDP packet has the following structure The salt is used to derive the per-session subkey and must be generated randomly to ensure uniqueness. Each UDP packet is encrypted/decrypted independently, using the derived subkey and a nonce with all zero bytes. AEAD stands for Authenticated Encryption with Associated Data. AEAD ciphers simultaneously provide confidentiality, integrity, and authenticity. They have excellent performance and power efficiency on modern hardware. Users should use AEAD ciphers whenever possible. The following AEAD ciphers are recommended. Compliant Shadowsocks implementations must support AEAD_CHACHA20_POLY1305. Implementations for devices with hardware AES acceleration should also implement AEAD_AES_128_GCM and AEAD_AES_256_GCM. Please refer to IANA AEAD registry for naming scheme and specification. The way Shadowsocks using AEAD ciphers is specified in SIP004 and amended in SIP007. SIP004 was proposed by @Mygod with design inspirations from @wongsyrone, @Noisyfox and @breakwa11. SIP007 was proposed by @riobard with input from @madeye, @Mygod, @wongsyrone, and many others. The master key can be input directly from user or generated from a password. The key derivation is still following EVP_BytesToKey(3) in OpenSSL. The detailed spec can be found here HKDF_SHA1 is a function that takes a secret key, a non-secret salt, an info string, and produces a subkey that is cryptographically strong even if the input secret key is weak. The info string binds the generated subkey to a specific application context. In our case, it must be the string "ss-subkey" without quotes. We derive a per-session subkey from a pre-shared master key using HKDF_SHA1. Salt must be unique through the entire life of the pre-shared master key. AE_encrypt is a function that takes a secret key, a non-secret nonce, a message, and produces ciphertext and authentication tag. Nonce must be unique for a given key in each invocation. AE_decrypt is a function that takes a secret key, non-secret nonce, ciphertext, authentication tag, and produces original message. If any of the input is tampered with, decryption will fail. An AEAD encrypted TCP stream starts with a randomly generated salt to derive the per-session subkey, followed by any number of encrypted chunks. Each chunk has the following structure: Payload length is a 2-byte big-endian unsigned integer capped at 0x3FFF. The higher two bits are reserved and must be set to zero. Payload is therefore limited to 16*1024 - 1 bytes. The first AEAD encrypt/decrypt operation uses a counting nonce starting from 0. After each encrypt/decrypt operation, the nonce is incremented by one as if it were an unsigned little-endian integer. Note that each TCP chunk involves two AEAD encrypt/decrypt operation: one for the payload length, and one for the payload. Therefore each chunk increases the nonce twice. An AEAD encrypted UDP packet has the following structure The salt is used to derive the per-session subkey and must be generated randomly to ensure uniqueness. Each UDP packet is encrypted/decrypted independently, using the derived subkey and a nonce with all zero bytes. Shadowsocks accepts JSON format configs like this: Shadowsocks accepts JSON format configs like this: The creator of shadowsocks and the maintainer of shadowsocks-python/nodejs/gui/iOS. The maintainer of shadowsocks-rust. The maintainer of shadowsocks-go and cow. The maintainer of shadowsocks-libev/android and this project site. The maintainer of shadowsocks-libev and MobileShadowSocks. The maintainer of shadowsocks-android. The maintainer of openwrt-shadowsocks. The maintainer of shadowsocks-qt5 and libQtShadowsocks The maintainer of GoAgentX. The maintainer of fqrouter. The creator of shadowsocks and the maintainer of shadowsocks-python/nodejs/gui/iOS. The maintainer of shadowsocks-rust. The maintainer of shadowsocks-go and cow. The maintainer of shadowsocks-libev/android and this project site. The maintainer of shadowsocks-libev and MobileShadowSocks. The maintainer of shadowsocks-android. The maintainer of openwrt-shadowsocks. The maintainer of shadowsocks-qt5 and libQtShadowsocks The maintainer of GoAgentX. The maintainer of fqrouter. First, buy a server from any cloud provider. DigitalOcean is recommended by us: Then, install Linux on your servers, Ubuntu 20.04 is recommended. shadowsocks-python is the initial version written by @clowwindy. It aims to provide a simple-to-use and easy-to-deploy implementation with basic features of shadowsocks. First, make sure you have Python 2.6 or 2.7. First, buy a server from any cloud provider. DigitalOcean is recommended by us: Then, install Linux on your servers, Ubuntu 20.04 is recommended. shadowsocks-python is the initial version written by @clowwindy. It aims to provide a simple-to-use and easy-to-deploy implementation with basic features of shadowsocks. First, make sure you have Python 2.6 or 2.7. Then install from PIP Checkout the source codes and run the scripts directly. https://github.com/shadowsocks shadowsocks-python is licensed under the Apache License, Version 2.0. go-shadowsocks2 is the next-generation Shadowsocks in Go, maintained by @riobard, supersedes the discontinued shadowsocks-go. Use go-shadowsocks2 is licensed under the Apache License, Version 2.0. outline-ss-server is the shadowsocks implementation used by the Outline Server, but it can be used standalone. Main features: Download pre-built binaries from the GitHub releases or build it from source: outline-ss-server is licensed under the Apache License, Version 2.0. shadowsocks-libev is a lightweight and full featured port for embedded devices and low end boxes. It's a pure C implementation and has a very small footprint (several megabytes) for thousands of connections. This port is maintained by @madeye. shadowsocks-libev is available in the official repository for Debian 9("Stretch"), unstable, Ubuntu 16.10 and later derivatives: For Debian Jessie users, please install it from jessie-backports: First, you need to pick a shadowsocks server and client implementation. Any implementation below is compatible with each other. First, you need to pick a shadowsocks server and client implementation. Any implementation below is compatible with each other. SIP002 purposed a new URI scheme, following RFC3986: SIP002 purposed a new URI scheme, following RFC3986: Note that encoding The last For plugin argument, we use the similar format as Examples: With user info encoded with Base64URL: Plain user info: FAQ: Q1: Why parse user info to Base64URL? A1: To safely encode all the characters in the key string. Note that we never try to "encrypt" your key in the URI. Q2: Why not parse host name and port number into Base64URL? A2: As mentioned above, we never try to "encrypt" anything in the URI. Additional parsing of host name and port number is not necessary. Q3: Why not every client supports SIP002 URI scheme? A3: Currently, SIP002 is still an optional feature unless the client supports SIP003 plugin. Q4: Why the tags with space is truncated? A4: White space is not legal in URI. It should be escaped. For example, The plugin of shadowsocks is very similar to the Pluggable Transport plugins from Tor project. Unlike the SOCKS5 proxy design in PT, every SIP003 plugin works as a tunnel (or called local port forwarding). This design aims to avoid per-connection arguments in PT, leading to much easier implementation. The plugin of shadowsocks is very similar to the Pluggable Transport plugins from Tor project. Unlike the SOCKS5 proxy design in PT, every SIP003 plugin works as a tunnel (or called local port forwarding). This design aims to avoid per-connection arguments in PT, leading to much easier implementation. This specification defines a standard JSON document format for online configuration sharing and delivery, along with guidelines and security considerations for the secure transport of server configurations. An example of a standard SIP008 JSON document: This specification defines a standard JSON document format for online configuration sharing and delivery, along with guidelines and security considerations for the secure transport of server configurations. An example of a standard SIP008 JSON document: This document defines the 2022 Edition of the Shadowsocks protocol. Improving upon Shadowsocks AEAD (2017), Shadowsocks 2022 addresses well-known issues of the previous editions, drops usage of obsolete cryptography, optimizes for security and performance, and leaves room for future extensions. Shadowsocks 2022 is a secure proxy protocol for TCP and UDP traffic. The protocol uses AEAD with a pre-shared symmetric key to protect payload integrity and confidentiality. The proxy traffic is indistinguishable from a random byte stream, and therefore can circumvent firewalls and Internet censors that rely on DPI (Deep Packet Inspection). Compared to previous editions of the protocol family, Shadowsocks 2022 allows and mandates full replay protection. Each message has its unique type and cannot be used for unintended purposes. The session-based UDP proxying significantly reduces protocol overhead and improves reliability and efficiency. Obsolete cryptographic functions have been replaced by their modern counterparts. As with previous editions, Shadowsocks 2022 does not provide forward secrecy. It is believed that using a pre-shared key without performing handshakes is best for its use cases. A Shadowsocks 2022 implementation consists of a server, a client, and optionally a relay. This document specifies requirements that implementations must follow. This document describes the Shadowsocks 2022 Edition and is structured as follows: The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 RFC2119 RFC8174 when, and only when, they appear in all capitals, as shown here. Commonly used terms in this document are described below. A pre-shared key is used to derive session subkeys, which are subsequently used to encrypt/decrypt traffic for the session. The pre-shared key is also used directly in some places. Unlike previous editions, Shadowsocks 2022 requires that a cryptographically-secure fixed-length PSK to be directly provided by the user. Implementations MUST NOT use the old The PSK is encoded in base64 for convenience. Practically, it can be generated with Shadowsocks 2022's subkey derivation uses BLAKE3's key derivation mode, which replaces the obsolete HKDF_SHA1 function in previous editions. A randomly generated salt is appended to the PSK to be used as key material. The salt has the same length as the pre-shared key. Method TCP connections over a Shadowsocks 2022 tunnel maps 1:1 to proxy connections. Each proxy connection carries 2 proxy streams: request stream and response stream. A client initiates a proxy connection by starting a request stream, and the server sends back response over the response stream. These streams carry chunks of data encrypted by the session subkey. For payload transfer, Shadowsocks 2022 inherits the length-chunk-payload-chunk model from Shadowsocks AEAD, with some minor tweaks to improve performance. Standalone header chunks are added to both request and response streams to improve security and protect against replay attacks. Each proxy stream derives its own session subkey with a random salt for encryption and decryption. A 12-byte little-endian integer is used as nonce, and is incremented after each encryption or decryption operation. This document defines the 2022 Edition of the Shadowsocks protocol. Improving upon Shadowsocks AEAD (2017), Shadowsocks 2022 addresses well-known issues of the previous editions, drops usage of obsolete cryptography, optimizes for security and performance, and leaves room for future extensions. Shadowsocks 2022 is a secure proxy protocol for TCP and UDP traffic. The protocol uses AEAD with a pre-shared symmetric key to protect payload integrity and confidentiality. The proxy traffic is indistinguishable from a random byte stream, and therefore can circumvent firewalls and Internet censors that rely on DPI (Deep Packet Inspection). Compared to previous editions of the protocol family, Shadowsocks 2022 allows and mandates full replay protection. Each message has its unique type and cannot be used for unintended purposes. The session-based UDP proxying significantly reduces protocol overhead and improves reliability and efficiency. Obsolete cryptographic functions have been replaced by their modern counterparts. As with previous editions, Shadowsocks 2022 does not provide forward secrecy. It is believed that using a pre-shared key without performing handshakes is best for its use cases. A Shadowsocks 2022 implementation consists of a server, a client, and optionally a relay. This document specifies requirements that implementations must follow. This document describes the Shadowsocks 2022 Edition and is structured as follows: The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 RFC2119 RFC8174 when, and only when, they appear in all capitals, as shown here. Commonly used terms in this document are described below. A pre-shared key is used to derive session subkeys, which are subsequently used to encrypt/decrypt traffic for the session. The pre-shared key is also used directly in some places. Unlike previous editions, Shadowsocks 2022 requires that a cryptographically-secure fixed-length PSK to be directly provided by the user. Implementations MUST NOT use the old The PSK is encoded in base64 for convenience. Practically, it can be generated with Shadowsocks 2022's subkey derivation uses BLAKE3's key derivation mode, which replaces the obsolete HKDF_SHA1 function in previous editions. A randomly generated salt is appended to the PSK to be used as key material. The salt has the same length as the pre-shared key. Method TCP connections over a Shadowsocks 2022 tunnel maps 1:1 to proxy connections. Each proxy connection carries 2 proxy streams: request stream and response stream. A client initiates a proxy connection by starting a request stream, and the server sends back response over the response stream. These streams carry chunks of data encrypted by the session subkey. For payload transfer, Shadowsocks 2022 inherits the length-chunk-payload-chunk model from Shadowsocks AEAD, with some minor tweaks to improve performance. Standalone header chunks are added to both request and response streams to improve security and protect against replay attacks. Each proxy stream derives its own session subkey with a random salt for encryption and decryption. A 12-byte little-endian integer is used as nonce, and is incremented after each encryption or decryption operation. A request stream starts with one random salt and two standalone header chunks, followed repeatedly by one length chunk and one payload chunk. Each chunk is independently encrypted/decrypted using the AEAD cipher. A response stream also starts with a random salt, but only has one fixed-length header chunk, which also acts as the first length chunk. A length chunk is a 16-bit big-endian unsigned integer that describes the payload length in the next payload chunk. Servers and clients rely on length chunks to know how many bytes to read for the next payload chunk. A payload chunk can have up to 0xFFFF (65535) bytes of unencrypted payload. The 0x3FFF (16383) length cap in Shadowsocks AEAD does not apply to this edition. Identity headers are one or more additional layers of headers, each consisting of the next layer's PSK hash. The next layer of an identity header is the next identity header, or the protocol header if it's the last identity header. Identity headers are encrypted with the current layer's identity PSK using an AES block cipher. Identity headers are implemented in such a way that's fully backward compatible with current Shadowsocks 2022 implementations. Each identity processor is fully transparent to the next. In TCP requests, identity headers are located between salt and AEAD chunks. Identity headers are one or more additional layers of headers, each consisting of the next layer's PSK hash. The next layer of an identity header is the next identity header, or the protocol header if it's the last identity header. Identity headers are encrypted with the current layer's identity PSK using an AES block cipher. Identity headers are implemented in such a way that's fully backward compatible with current Shadowsocks 2022 implementations. Each identity processor is fully transparent to the next. In TCP requests, identity headers are located between salt and AEAD chunks. In UDP packets, identity headers are located between the separate header (session ID, packet ID) and AEAD ciphertext. When iPSKs are used, the separate header MUST be encrypted with the first iPSK. Each identity processor MUST decrypt and re-encrypt the separate header with the next layer's PSK. Stream ciphers are completely broken and will be removed soon. New users must use AEAD ciphers. This historic document is for educational purposes only. Stream_encrypt is a function that takes a secret key, an initialization vector, a message, and produces a ciphertext with the same length as the message. Stream_decrypt is a function that takes a secret key, an initializaiton vector, a ciphertext, and produces the original message. The key can be input directly from user or generated from a password. The key derivation is following A stream cipher encrypted TCP stream starts with a randomly generated initializaiton vector, followed by encrypted payload data. A stream cipher encrypted UDP packet has the following structure Each UDP packet is encrypted/decrypted independently with a randomly generated initialization vector. Stream ciphers are completely broken and will be removed soon. New users must use AEAD ciphers. This historic document is for educational purposes only. Stream_encrypt is a function that takes a secret key, an initialization vector, a message, and produces a ciphertext with the same length as the message. Stream_decrypt is a function that takes a secret key, an initializaiton vector, a ciphertext, and produces the original message. The key can be input directly from user or generated from a password. The key derivation is following A stream cipher encrypted TCP stream starts with a randomly generated initializaiton vector, followed by encrypted payload data. A stream cipher encrypted UDP packet has the following structure Each UDP packet is encrypted/decrypted independently with a randomly generated initialization vector. Shadowsocks is a secure split proxy loosely based on SOCKS5. The Shadowsocks local component (ss-local) acts like a traditional SOCKS5 server and provides proxy service to clients. It encrypts and forwards data streams and packets from the client to the Shadowsocks remote component (ss-remote), which decrypts and forwards to the target. Replies from target are similarly encrypted and relayed by ss-remote back to ss-local, which decrypts and eventually returns to the original client. Addresses used in Shadowsocks follow the SOCKS5 address format: The following address types are defined: The port number is a 2-byte big-endian unsigned integer. ss-local initiates a TCP connection to ss-remote by sending an encrypted data stream starting with the target address followed by payload data. The exact encryption scheme differs depending on the cipher used. ss-remote receives the encrypted data stream, decrypts and parses the leading target address. It then establishes a new TCP connection to the target and forwards payload data to it. ss-remote receives reply from the target, encrypts and forwards it back to the ss-local, until ss-local disconnects. For better obfuscation purposes, both local and remote SHOULD send the handshake data along with some payload in the first packet. ss-local sends an encrypted data packet containing the target address and payload to ss-remote. Upon receiving the encrypted packet, ss-remote decrypts and parses the target address. It then sends a new data packet containing only the payload to the target. ss-remote receives data packets back from target and prepends the target address to the payload in each packet, then sends encrypted copies back to ss-local. Essentially, ss-remote is performing Network Address Translation for ss-local. Shadowsocks is a secure split proxy loosely based on SOCKS5. The Shadowsocks local component (ss-local) acts like a traditional SOCKS5 server and provides proxy service to clients. It encrypts and forwards data streams and packets from the client to the Shadowsocks remote component (ss-remote), which decrypts and forwards to the target. Replies from target are similarly encrypted and relayed by ss-remote back to ss-local, which decrypts and eventually returns to the original client. Addresses used in Shadowsocks follow the SOCKS5 address format: The following address types are defined: The port number is a 2-byte big-endian unsigned integer. ss-local initiates a TCP connection to ss-remote by sending an encrypted data stream starting with the target address followed by payload data. The exact encryption scheme differs depending on the cipher used. ss-remote receives the encrypted data stream, decrypts and parses the leading target address. It then establishes a new TCP connection to the target and forwards payload data to it. ss-remote receives reply from the target, encrypts and forwards it back to the ss-local, until ss-local disconnects. For better obfuscation purposes, both local and remote SHOULD send the handshake data along with some payload in the first packet. ss-local sends an encrypted data packet containing the target address and payload to ss-remote. Upon receiving the encrypted packet, ss-remote decrypts and parses the target address. It then sends a new data packet containing only the payload to the target. ss-remote receives data packets back from target and prepends the target address to the payload in each packet, then sends encrypted copies back to ss-local. Essentially, ss-remote is performing Network Address Translation for ss-local. SIP stands for Shadowsocks Improvement Proposal. SIPs are standards specifying potential new features or processes for Shadowsocks. Shadowsocks is a community open to any reasonable improvements. To submit a SIP, please open a SIP issue on our GitHub issue tracker. If most of the core contributors agree to accept a SIP, a formal SIP document will be published on this site. All the developers will review and follow the SIP to implement their own implementations. The whole process usually takes months. SIP stands for Shadowsocks Improvement Proposal. SIPs are standards specifying potential new features or processes for Shadowsocks. Shadowsocks is a community open to any reasonable improvements. To submit a SIP, please open a SIP issue on our GitHub issue tracker. If most of the core contributors agree to accept a SIP, a formal SIP document will be published on this site. All the developers will review and follow the SIP to implement their own implementations. The whole process usually takes months. Of course, remember to execute PAGE NOT FOUND
But if you don't change your direction, and if you keep looking, you may end up where you are heading.
Advanced configurations
Optimize the shadowsocks server on Linux
Step 1, increase the maximum number of open file descriptors
limits.conf
vi /etc/security/limits.conf
* soft nofile 51200
+import{_ as s,c as e,o as a,R as n}from"./chunks/framework.bdd825cc.js";const u=JSON.parse('{"title":"Advanced configurations","description":"","frontmatter":{},"headers":[],"relativePath":"doc/advanced.md","filePath":"doc/advanced.md","lastUpdated":1692058814000}'),o={name:"doc/advanced.md"},t=n(`
Advanced configurations
Optimize the shadowsocks server on Linux
Step 1, increase the maximum number of open file descriptors
limits.conf
vi /etc/security/limits.conf
* soft nofile 51200
* hard nofile 51200
# for server running in root:
diff --git a/assets/doc_advanced.md.ebd27102.lean.js b/assets/doc_advanced.md.aaab6733.lean.js
similarity index 70%
rename from assets/doc_advanced.md.ebd27102.lean.js
rename to assets/doc_advanced.md.aaab6733.lean.js
index 8e07705..00fa777 100644
--- a/assets/doc_advanced.md.ebd27102.lean.js
+++ b/assets/doc_advanced.md.aaab6733.lean.js
@@ -1 +1 @@
-import{_ as s,c as e,o as a,R as n}from"./chunks/framework.bdd825cc.js";const u=JSON.parse('{"title":"Advanced configurations","description":"","frontmatter":{},"headers":[],"relativePath":"doc/advanced.md","filePath":"doc/advanced.md","lastUpdated":1691108507000}'),o={name:"doc/advanced.md"},t=n("",17),p=[t];function l(c,i,r,d,h,C){return a(),e("div",null,p)}const A=s(o,[["render",l]]);export{u as __pageData,A as default};
+import{_ as s,c as e,o as a,R as n}from"./chunks/framework.bdd825cc.js";const u=JSON.parse('{"title":"Advanced configurations","description":"","frontmatter":{},"headers":[],"relativePath":"doc/advanced.md","filePath":"doc/advanced.md","lastUpdated":1692058814000}'),o={name:"doc/advanced.md"},t=n("",17),p=[t];function l(c,i,r,d,h,C){return a(),e("div",null,p)}const A=s(o,[["render",l]]);export{u as __pageData,A as default};
diff --git a/assets/doc_aead.md.1974ef83.js b/assets/doc_aead.md.04b1947a.js
similarity index 99%
rename from assets/doc_aead.md.1974ef83.js
rename to assets/doc_aead.md.04b1947a.js
index 1b33afc..61e31cf 100644
--- a/assets/doc_aead.md.1974ef83.js
+++ b/assets/doc_aead.md.04b1947a.js
@@ -1 +1 @@
-import{_ as e,c as t,o as a,R as r}from"./chunks/framework.bdd825cc.js";const y=JSON.parse('{"title":"AEAD ciphers","description":"","frontmatter":{},"headers":[],"relativePath":"doc/aead.md","filePath":"doc/aead.md","lastUpdated":1691108507000}'),n={name:"doc/aead.md"},s=r('
AEAD ciphers
Name Alias Key Size Salt Size Nonce Size Tag Size AEAD_CHACHA20_POLY1305 chacha20-ietf-poly1305 32 32 12 16 AEAD_AES_256_GCM aes-256-gcm 32 32 12 16 AEAD_AES_128_GCM aes-128-gcm 16 16 12 16 Key Derivation
HKDF_SHA1(key, salt, info) => subkey
Authenticated Encryption/Decryption
AE_encrypt(key, nonce, message) => (ciphertext, tag)
AE_decrypt(key, nonce, ciphertext, tag) => message
TCP
[encrypted payload length][length tag][encrypted payload][payload tag]
UDP
[salt][encrypted payload][tag]
AEAD ciphers
Name Alias Key Size Salt Size Nonce Size Tag Size AEAD_CHACHA20_POLY1305 chacha20-ietf-poly1305 32 32 12 16 AEAD_AES_256_GCM aes-256-gcm 32 32 12 16 AEAD_AES_128_GCM aes-128-gcm 16 16 12 16 Key Derivation
HKDF_SHA1(key, salt, info) => subkey
Authenticated Encryption/Decryption
AE_encrypt(key, nonce, message) => (ciphertext, tag)
AE_decrypt(key, nonce, ciphertext, tag) => message
TCP
[encrypted payload length][length tag][encrypted payload][payload tag]
UDP
[salt][encrypted payload][tag]
Config Format
Config File
{
+import{_ as s,c as e,o as a,R as o}from"./chunks/framework.bdd825cc.js";const y=JSON.parse('{"title":"Config Format","description":"","frontmatter":{},"headers":[],"relativePath":"doc/configs.md","filePath":"doc/configs.md","lastUpdated":1692058814000}'),n={name:"doc/configs.md"},t=o(`
Config Format
Config File
{
"server":"my_server_ip",
"server_port":8388,
"local_port":1080,
diff --git a/assets/doc_configs.md.0022fb0d.lean.js b/assets/doc_configs.md.ffd0c0d9.lean.js
similarity index 84%
rename from assets/doc_configs.md.0022fb0d.lean.js
rename to assets/doc_configs.md.ffd0c0d9.lean.js
index eadba95..20feffc 100644
--- a/assets/doc_configs.md.0022fb0d.lean.js
+++ b/assets/doc_configs.md.ffd0c0d9.lean.js
@@ -1 +1 @@
-import{_ as s,c as e,o as a,R as o}from"./chunks/framework.bdd825cc.js";const y=JSON.parse('{"title":"Config Format","description":"","frontmatter":{},"headers":[],"relativePath":"doc/configs.md","filePath":"doc/configs.md","lastUpdated":1691108507000}'),n={name:"doc/configs.md"},t=o("",21),l=[t];function p(c,r,i,d,h,u){return a(),e("div",null,l)}const F=s(n,[["render",p]]);export{y as __pageData,F as default};
+import{_ as s,c as e,o as a,R as o}from"./chunks/framework.bdd825cc.js";const y=JSON.parse('{"title":"Config Format","description":"","frontmatter":{},"headers":[],"relativePath":"doc/configs.md","filePath":"doc/configs.md","lastUpdated":1692058814000}'),n={name:"doc/configs.md"},t=o("",21),l=[t];function p(c,r,i,d,h,u){return a(),e("div",null,l)}const F=s(n,[["render",p]]);export{y as __pageData,F as default};
diff --git a/assets/doc_contributors.md.9beacabb.js b/assets/doc_contributors.md.4e813132.js
similarity index 95%
rename from assets/doc_contributors.md.9beacabb.js
rename to assets/doc_contributors.md.4e813132.js
index b680814..41eabfe 100644
--- a/assets/doc_contributors.md.9beacabb.js
+++ b/assets/doc_contributors.md.4e813132.js
@@ -1 +1 @@
-import{_ as r,c as e,o as t,R as o}from"./chunks/framework.bdd825cc.js";const u=JSON.parse('{"title":"Contributors","description":"","frontmatter":{},"headers":[],"relativePath":"doc/contributors.md","filePath":"doc/contributors.md","lastUpdated":1691108507000}'),a={name:"doc/contributors.md"},n=o('
Contributors
Core Contributors
Other Contributors
Contributors
Core Contributors
Other Contributors
Deploying
Setup your own server
Python
PyPI
$ python --version
+import{_ as s,c as a,o as e,R as o}from"./chunks/framework.bdd825cc.js";const y=JSON.parse('{"title":"Deploying","description":"","frontmatter":{},"headers":[],"relativePath":"doc/deploying.md","filePath":"doc/deploying.md","lastUpdated":1692058814000}'),n={name:"doc/deploying.md"},l=o(`
Deploying
Setup your own server
Python
PyPI
$ python --version
Python 2.6.8
$ pip install shadowsocks
GitHub
Go
GitHub
go get
to install.$ go get -u -v github.com/shadowsocks/go-shadowsocks2
Go from Outline
GitHub
go get github.com/Jigsaw-code/outline-ss-server
$(go env GOPATH)/bin/outline-ss-server -config=config.yml -metrics=127.0.0.1:9091
C with libev
Debian/Ubuntu:
sudo apt update
sudo apt install shadowsocks-libev
sudo sh -c 'printf "deb http://httpredir.debian.org/debian jessie-backports
diff --git a/assets/doc_deploying.md.78e0080e.lean.js b/assets/doc_deploying.md.c558b9e9.lean.js
similarity index 84%
rename from assets/doc_deploying.md.78e0080e.lean.js
rename to assets/doc_deploying.md.c558b9e9.lean.js
index a4694bc..3adaad7 100644
--- a/assets/doc_deploying.md.78e0080e.lean.js
+++ b/assets/doc_deploying.md.c558b9e9.lean.js
@@ -1 +1 @@
-import{_ as s,c as a,o as e,R as o}from"./chunks/framework.bdd825cc.js";const y=JSON.parse('{"title":"Deploying","description":"","frontmatter":{},"headers":[],"relativePath":"doc/deploying.md","filePath":"doc/deploying.md","lastUpdated":1691108507000}'),n={name:"doc/deploying.md"},l=o("",65),t=[l];function p(r,i,c,h,d,C){return e(),a("div",null,t)}const b=s(n,[["render",p]]);export{y as __pageData,b as default};
+import{_ as s,c as a,o as e,R as o}from"./chunks/framework.bdd825cc.js";const y=JSON.parse('{"title":"Deploying","description":"","frontmatter":{},"headers":[],"relativePath":"doc/deploying.md","filePath":"doc/deploying.md","lastUpdated":1692058814000}'),n={name:"doc/deploying.md"},l=o("",65),t=[l];function p(r,i,c,h,d,C){return e(),a("div",null,t)}const b=s(n,[["render",p]]);export{y as __pageData,b as default};
diff --git a/assets/doc_getting-started.md.4cb43a37.js b/assets/doc_getting-started.md.b448fa30.js
similarity index 98%
rename from assets/doc_getting-started.md.4cb43a37.js
rename to assets/doc_getting-started.md.b448fa30.js
index da3bbd7..7baf680 100644
--- a/assets/doc_getting-started.md.4cb43a37.js
+++ b/assets/doc_getting-started.md.b448fa30.js
@@ -1 +1 @@
-import{_ as t,c as d,o as s,R as a}from"./chunks/framework.bdd825cc.js";const p=JSON.parse('{"title":"Getting Started","description":"","frontmatter":{},"headers":[],"relativePath":"doc/getting-started.md","filePath":"doc/getting-started.md","lastUpdated":1691108507000}'),e={name:"doc/getting-started.md"},o=a('
Getting Started
CLI implementations
Feature comparison
ss ss-libev go-ss2 ss-rust TCP Fast Open ✓ ✓ ✗ ✓ Multiuser ✓ ✓ ✗ ✓ Management API ✓ ✓ ✗ ✓ Redirect mode ✗ ✓ ✓ ✓ Tunnel mode ✓ ✓ ✓ ✓ UDP Relay ✓ ✓ ✓ ✓ MPTCP ✗ ✓ ✗ ✓ AEAD ciphers ✓ ✓ ✓ ✓ Plugin ✗ ✓ ✗ ✓ Plugin UDP (Experimental) ✗ ✗ ✗ ✓ GUI Clients
Feature comparison
',10),r=[o];function h(i,n,c,l,m,u){return s(),d("div",null,r)}const g=t(e,[["render",h]]);export{p as __pageData,g as default};
+import{_ as t,c as d,o as s,R as a}from"./chunks/framework.bdd825cc.js";const p=JSON.parse('{"title":"Getting Started","description":"","frontmatter":{},"headers":[],"relativePath":"doc/getting-started.md","filePath":"doc/getting-started.md","lastUpdated":1692058814000}'),e={name:"doc/getting-started.md"},o=a('ss-win ssx-ng ss-qt5 ss-android System Proxy ✓ ✓ ✗ ✓ CHNRoutes ✓ ✓ ✗ ✓ PAC Configuration ✓ ✓ ✗ ✗ Profile Switching ✓ ✓ ✓ ✓ QR Code Scan ✓ ✓ ✓ ✓ QR Code Generation ✓ ✓ ✓ ✓ Getting Started
CLI implementations
Feature comparison
ss ss-libev go-ss2 ss-rust TCP Fast Open ✓ ✓ ✗ ✓ Multiuser ✓ ✓ ✗ ✓ Management API ✓ ✓ ✗ ✓ Redirect mode ✗ ✓ ✓ ✓ Tunnel mode ✓ ✓ ✓ ✓ UDP Relay ✓ ✓ ✓ ✓ MPTCP ✗ ✓ ✗ ✓ AEAD ciphers ✓ ✓ ✓ ✓ Plugin ✗ ✓ ✗ ✓ Plugin UDP (Experimental) ✗ ✗ ✗ ✓ GUI Clients
Feature comparison
',10),r=[o];function h(i,n,c,l,m,u){return s(),d("div",null,r)}const g=t(e,[["render",h]]);export{p as __pageData,g as default};
diff --git a/assets/doc_getting-started.md.4cb43a37.lean.js b/assets/doc_getting-started.md.b448fa30.lean.js
similarity index 85%
rename from assets/doc_getting-started.md.4cb43a37.lean.js
rename to assets/doc_getting-started.md.b448fa30.lean.js
index ff7a0b5..998c4cd 100644
--- a/assets/doc_getting-started.md.4cb43a37.lean.js
+++ b/assets/doc_getting-started.md.b448fa30.lean.js
@@ -1 +1 @@
-import{_ as t,c as d,o as s,R as a}from"./chunks/framework.bdd825cc.js";const p=JSON.parse('{"title":"Getting Started","description":"","frontmatter":{},"headers":[],"relativePath":"doc/getting-started.md","filePath":"doc/getting-started.md","lastUpdated":1691108507000}'),e={name:"doc/getting-started.md"},o=a("",10),r=[o];function h(i,n,c,l,m,u){return s(),d("div",null,r)}const g=t(e,[["render",h]]);export{p as __pageData,g as default};
+import{_ as t,c as d,o as s,R as a}from"./chunks/framework.bdd825cc.js";const p=JSON.parse('{"title":"Getting Started","description":"","frontmatter":{},"headers":[],"relativePath":"doc/getting-started.md","filePath":"doc/getting-started.md","lastUpdated":1692058814000}'),e={name:"doc/getting-started.md"},o=a("",10),r=[o];function h(i,n,c,l,m,u){return s(),d("div",null,r)}const g=t(e,[["render",h]]);export{p as __pageData,g as default};
diff --git a/assets/doc_sip002.md.f9137dc5.js b/assets/doc_sip002.md.bdd62ea4.js
similarity index 98%
rename from assets/doc_sip002.md.f9137dc5.js
rename to assets/doc_sip002.md.bdd62ea4.js
index 9f8e308..ba4d5ee 100644
--- a/assets/doc_sip002.md.f9137dc5.js
+++ b/assets/doc_sip002.md.bdd62ea4.js
@@ -1,3 +1,3 @@
-import{_ as e,c as s,o,R as t}from"./chunks/framework.bdd825cc.js";const f=JSON.parse('{"title":"SIP002 URI scheme","description":"","frontmatter":{},"headers":[],"relativePath":"doc/sip002.md","filePath":"doc/sip002.md","lastUpdated":1691108507000}'),a={name:"doc/sip002.md"},n=t(`ss-win ssx-ng ss-qt5 ss-android System Proxy ✓ ✓ ✗ ✓ CHNRoutes ✓ ✓ ✗ ✓ PAC Configuration ✓ ✓ ✗ ✗ Profile Switching ✓ ✓ ✓ ✓ QR Code Scan ✓ ✓ ✓ ✓ QR Code Generation ✓ ✓ ✓ ✓ SIP002 URI scheme
SS-URI = "ss://" userinfo "@" hostname ":" port [ "/" ] [ "?" plugin ] [ "#" tag ]
+import{_ as e,c as s,o,R as t}from"./chunks/framework.bdd825cc.js";const f=JSON.parse('{"title":"SIP002 URI scheme","description":"","frontmatter":{},"headers":[],"relativePath":"doc/sip002.md","filePath":"doc/sip002.md","lastUpdated":1692058814000}'),a={name:"doc/sip002.md"},n=t(`
SIP002 URI scheme
SS-URI = "ss://" userinfo "@" hostname ":" port [ "/" ] [ "?" plugin ] [ "#" tag ]
userinfo = websafe-base64-encode-utf8(method ":" password)
method ":" password
userinfo
with Base64URL is recommended but optional for Stream and AEAD (SIP004). But for AEAD-2022 (SIP022), userinfo
MUST NOT be encoded with Base64URL. When userinfo
is not encoded, method
and password
MUST be percent encoded./
should be appended if plugin is present, but is optional if only tag is present. Example: ss://YmYtY2ZiOnRlc3Q@192.168.100.1:8888/?plugin=url-encoded-plugin-argument-value&unsupported-arguments=should-be-ignored#Dummy+profile+name
. This kind of URIs can be parsed by standard libraries provided by most languages.TOR_PT_SERVER_TRANSPORT_OPTIONS
, which have the format like simple-obfs;obfs=http;obfs-host=example.com
where colons, semicolons, equal signs and backslashes MUST be escaped with a backslash.ss://YWVzLTEyOC1nY206dGVzdA@192.168.100.1:8888#Example1
ss://cmM0LW1kNTpwYXNzd2Q@192.168.100.1:8888/?plugin=obfs-local%3Bobfs%3Dhttp#Example2
ss://2022-blake3-aes-256-gcm:YctPZ6U7xPPcU%2Bgp3u%2B0tx%2FtRizJN9K8y%2BuKlW2qjlI%3D@192.168.100.1:8888#Example3
ss://2022-blake3-aes-256-gcm:YctPZ6U7xPPcU%2Bgp3u%2B0tx%2FtRizJN9K8y%2BuKlW2qjlI%3D@192.168.100.1:8888/?plugin=v2ray-plugin%3Bserver#Example3
ss://...#shadowsocks server 1
(illegal URI) should be escaped into ss://...#shadowsocks%20server%201
(legal URI).SIP003: A simplified plugin design for shadowsocks
Architecture Overview
+------------+ +---------------------------+
+import{_ as e,c as s,o as a,R as o}from"./chunks/framework.bdd825cc.js";const f=JSON.parse('{"title":"SIP003: A simplified plugin design for shadowsocks","description":"","frontmatter":{},"headers":[],"relativePath":"doc/sip003.md","filePath":"doc/sip003.md","lastUpdated":1692058814000}'),n={name:"doc/sip003.md"},t=o(`
SIP003: A simplified plugin design for shadowsocks
Architecture Overview
+------------+ +---------------------------+
| SS Client +-- Local Loopback --+ Plugin Client (Tunnel) +--+
+------------+ +---------------------------+ |
|
diff --git a/assets/doc_sip003.md.16f3d54d.lean.js b/assets/doc_sip003.md.a00aec58.lean.js
similarity index 85%
rename from assets/doc_sip003.md.16f3d54d.lean.js
rename to assets/doc_sip003.md.a00aec58.lean.js
index 7835bf0..5c8fdfe 100644
--- a/assets/doc_sip003.md.16f3d54d.lean.js
+++ b/assets/doc_sip003.md.a00aec58.lean.js
@@ -1 +1 @@
-import{_ as e,c as s,o as a,R as o}from"./chunks/framework.bdd825cc.js";const f=JSON.parse('{"title":"SIP003: A simplified plugin design for shadowsocks","description":"","frontmatter":{},"headers":[],"relativePath":"doc/sip003.md","filePath":"doc/sip003.md","lastUpdated":1691108507000}'),n={name:"doc/sip003.md"},t=o("",27),l=[t];function r(i,p,c,h,d,u){return a(),s("div",null,l)}const m=e(n,[["render",r]]);export{f as __pageData,m as default};
+import{_ as e,c as s,o as a,R as o}from"./chunks/framework.bdd825cc.js";const f=JSON.parse('{"title":"SIP003: A simplified plugin design for shadowsocks","description":"","frontmatter":{},"headers":[],"relativePath":"doc/sip003.md","filePath":"doc/sip003.md","lastUpdated":1692058814000}'),n={name:"doc/sip003.md"},t=o("",27),l=[t];function r(i,p,c,h,d,u){return a(),s("div",null,l)}const m=e(n,[["render",r]]);export{f as __pageData,m as default};
diff --git a/assets/doc_sip008.md.990988e0.js b/assets/doc_sip008.md.f8790501.js
similarity index 99%
rename from assets/doc_sip008.md.990988e0.js
rename to assets/doc_sip008.md.f8790501.js
index 2c7b052..06ff8fb 100644
--- a/assets/doc_sip008.md.990988e0.js
+++ b/assets/doc_sip008.md.f8790501.js
@@ -1,4 +1,4 @@
-import{_ as e,c as s,o as n,R as a}from"./chunks/framework.bdd825cc.js";const f=JSON.parse('{"title":"SIP008 Online Configuration Delivery","description":"","frontmatter":{},"headers":[],"relativePath":"doc/sip008.md","filePath":"doc/sip008.md","lastUpdated":1691108507000}'),o={name:"doc/sip008.md"},t=a(`
SIP008 Online Configuration Delivery
JSON Document Format
{
+import{_ as e,c as s,o as n,R as a}from"./chunks/framework.bdd825cc.js";const f=JSON.parse('{"title":"SIP008 Online Configuration Delivery","description":"","frontmatter":{},"headers":[],"relativePath":"doc/sip008.md","filePath":"doc/sip008.md","lastUpdated":1692058814000}'),o={name:"doc/sip008.md"},t=a(`
SIP008 Online Configuration Delivery
JSON Document Format
{
"version": 1,
"servers": [
{
diff --git a/assets/doc_sip008.md.990988e0.lean.js b/assets/doc_sip008.md.f8790501.lean.js
similarity index 85%
rename from assets/doc_sip008.md.990988e0.lean.js
rename to assets/doc_sip008.md.f8790501.lean.js
index 8664dac..b6792ec 100644
--- a/assets/doc_sip008.md.990988e0.lean.js
+++ b/assets/doc_sip008.md.f8790501.lean.js
@@ -1 +1 @@
-import{_ as e,c as s,o as n,R as a}from"./chunks/framework.bdd825cc.js";const f=JSON.parse('{"title":"SIP008 Online Configuration Delivery","description":"","frontmatter":{},"headers":[],"relativePath":"doc/sip008.md","filePath":"doc/sip008.md","lastUpdated":1691108507000}'),o={name:"doc/sip008.md"},t=a("",8),i=[t];function l(r,p,c,d,u,h){return n(),s("div",null,i)}const y=e(o,[["render",l]]);export{f as __pageData,y as default};
+import{_ as e,c as s,o as n,R as a}from"./chunks/framework.bdd825cc.js";const f=JSON.parse('{"title":"SIP008 Online Configuration Delivery","description":"","frontmatter":{},"headers":[],"relativePath":"doc/sip008.md","filePath":"doc/sip008.md","lastUpdated":1692058814000}'),o={name:"doc/sip008.md"},t=a("",8),i=[t];function l(r,p,c,d,u,h){return n(),s("div",null,i)}const y=e(o,[["render",l]]);export{f as __pageData,y as default};
diff --git a/assets/doc_sip022.md.61022497.js b/assets/doc_sip022.md.10538951.js
similarity index 99%
rename from assets/doc_sip022.md.61022497.js
rename to assets/doc_sip022.md.10538951.js
index 4e352f0..fd0ce30 100644
--- a/assets/doc_sip022.md.61022497.js
+++ b/assets/doc_sip022.md.10538951.js
@@ -1,4 +1,4 @@
-import{_ as e,c as s,o as a,R as n}from"./chunks/framework.bdd825cc.js";const A=JSON.parse('{"title":"SIP022 AEAD-2022 Ciphers","description":"","frontmatter":{},"headers":[],"relativePath":"doc/sip022.md","filePath":"doc/sip022.md","lastUpdated":1691108507000}'),t={name:"doc/sip022.md"},o=n(`
SIP022 AEAD-2022 Ciphers
Abstract
1. Overview
1.1. Document Structure
1.2. Terms and Definitions
2. Encryption/Decryption Keys
2.1. PSK
EVP_BytesToKey
function or any other method to generate keys from passwords.openssl rand -base64 <key_size>
. The key size depends on the chosen method. This change was inspired by WireGuard.Method Key Bytes Salt Bytes 2022-blake3-aes-128-gcm 16 16 2022-blake3-aes-256-gcm 32 32 2.2. Subkey Derivation
session_subkey := blake3::derive_key(context: "shadowsocks 2022 session subkey", key_material: key + salt)
3. Required Methods
2022-blake3-aes-128-gcm
and 2022-blake3-aes-256-gcm
MUST be implemented by all implementations. 2022
reflects the fast-changing and flexible nature of the protocol.3.1. TCP
3.1.1. Encryption and Decryption
u96le counter
+import{_ as e,c as s,o as a,R as n}from"./chunks/framework.bdd825cc.js";const A=JSON.parse('{"title":"SIP022 AEAD-2022 Ciphers","description":"","frontmatter":{},"headers":[],"relativePath":"doc/sip022.md","filePath":"doc/sip022.md","lastUpdated":1692058814000}'),t={name:"doc/sip022.md"},o=n(`
SIP022 AEAD-2022 Ciphers
Abstract
1. Overview
1.1. Document Structure
1.2. Terms and Definitions
2. Encryption/Decryption Keys
2.1. PSK
EVP_BytesToKey
function or any other method to generate keys from passwords.openssl rand -base64 <key_size>
. The key size depends on the chosen method. This change was inspired by WireGuard.Method Key Bytes Salt Bytes 2022-blake3-aes-128-gcm 16 16 2022-blake3-aes-256-gcm 32 32 2.2. Subkey Derivation
session_subkey := blake3::derive_key(context: "shadowsocks 2022 session subkey", key_material: key + salt)
3. Required Methods
2022-blake3-aes-128-gcm
and 2022-blake3-aes-256-gcm
MUST be implemented by all implementations. 2022
reflects the fast-changing and flexible nature of the protocol.3.1. TCP
3.1.1. Encryption and Decryption
u96le counter
aead := aead_new(key: session_subkey)
ciphertext := aead.seal(nonce: counter, plaintext)
plaintext := aead.open(nonce: counter, ciphertext)
3.1.2. Format
+----------------+
diff --git a/assets/doc_sip022.md.61022497.lean.js b/assets/doc_sip022.md.10538951.lean.js
similarity index 69%
rename from assets/doc_sip022.md.61022497.lean.js
rename to assets/doc_sip022.md.10538951.lean.js
index ca1a47e..a0825cc 100644
--- a/assets/doc_sip022.md.61022497.lean.js
+++ b/assets/doc_sip022.md.10538951.lean.js
@@ -1 +1 @@
-import{_ as e,c as s,o as a,R as n}from"./chunks/framework.bdd825cc.js";const A=JSON.parse('{"title":"SIP022 AEAD-2022 Ciphers","description":"","frontmatter":{},"headers":[],"relativePath":"doc/sip022.md","filePath":"doc/sip022.md","lastUpdated":1691108507000}'),t={name:"doc/sip022.md"},o=n("",86),r=[o];function i(l,p,c,d,h,y){return a(),s("div",null,r)}const m=e(t,[["render",i]]);export{A as __pageData,m as default};
+import{_ as e,c as s,o as a,R as n}from"./chunks/framework.bdd825cc.js";const A=JSON.parse('{"title":"SIP022 AEAD-2022 Ciphers","description":"","frontmatter":{},"headers":[],"relativePath":"doc/sip022.md","filePath":"doc/sip022.md","lastUpdated":1692058814000}'),t={name:"doc/sip022.md"},o=n("",86),r=[o];function i(l,p,c,d,h,y){return a(),s("div",null,r)}const m=e(t,[["render",i]]);export{A as __pageData,m as default};
diff --git a/assets/doc_sip023.md.b82317b8.js b/assets/doc_sip023.md.17c4bc0b.js
similarity index 99%
rename from assets/doc_sip023.md.b82317b8.js
rename to assets/doc_sip023.md.17c4bc0b.js
index e1c4fc2..cd15097 100644
--- a/assets/doc_sip023.md.b82317b8.js
+++ b/assets/doc_sip023.md.17c4bc0b.js
@@ -1,4 +1,4 @@
-import{_ as e,c as t,o as s,R as a}from"./chunks/framework.bdd825cc.js";const P=JSON.parse('{"title":"SIP023 Shadowsocks 2022 Extensible Identity Headers","description":"","frontmatter":{},"headers":[],"relativePath":"doc/sip023.md","filePath":"doc/sip023.md","lastUpdated":1691108507000}'),n={name:"doc/sip023.md"},i=a(`
SIP023 Shadowsocks 2022 Extensible Identity Headers
TCP
identity_subkey := blake3::derive_key(context: "shadowsocks 2022 identity subkey", key_material: iPSKn + salt)
+import{_ as e,c as t,o as s,R as a}from"./chunks/framework.bdd825cc.js";const P=JSON.parse('{"title":"SIP023 Shadowsocks 2022 Extensible Identity Headers","description":"","frontmatter":{},"headers":[],"relativePath":"doc/sip023.md","filePath":"doc/sip023.md","lastUpdated":1692058814000}'),n={name:"doc/sip023.md"},i=a(`
SIP023 Shadowsocks 2022 Extensible Identity Headers
TCP
identity_subkey := blake3::derive_key(context: "shadowsocks 2022 identity subkey", key_material: iPSKn + salt)
plaintext := blake3::hash(iPSKn+1)[0..16] // Take the first 16 bytes of the next iPSK's hash.
identity_header := aes_encrypt(key: identity_subkey, plaintext: plaintext)
UDP
plaintext := blake3::hash(iPSKn+1)[0..16] ^ session_id_packet_id // XOR to make it different for each packet.
identity_header := aes_encrypt(key: iPSKn, plaintext: plaintext)
Scenarios
client0 >---+
diff --git a/assets/doc_sip023.md.b82317b8.lean.js b/assets/doc_sip023.md.17c4bc0b.lean.js
similarity index 85%
rename from assets/doc_sip023.md.b82317b8.lean.js
rename to assets/doc_sip023.md.17c4bc0b.lean.js
index 8d64224..bd572b9 100644
--- a/assets/doc_sip023.md.b82317b8.lean.js
+++ b/assets/doc_sip023.md.17c4bc0b.lean.js
@@ -1 +1 @@
-import{_ as e,c as t,o as s,R as a}from"./chunks/framework.bdd825cc.js";const P=JSON.parse('{"title":"SIP023 Shadowsocks 2022 Extensible Identity Headers","description":"","frontmatter":{},"headers":[],"relativePath":"doc/sip023.md","filePath":"doc/sip023.md","lastUpdated":1691108507000}'),n={name:"doc/sip023.md"},i=a("",21),r=[i];function o(d,c,l,p,h,y){return s(),t("div",null,r)}const S=e(n,[["render",o]]);export{P as __pageData,S as default};
+import{_ as e,c as t,o as s,R as a}from"./chunks/framework.bdd825cc.js";const P=JSON.parse('{"title":"SIP023 Shadowsocks 2022 Extensible Identity Headers","description":"","frontmatter":{},"headers":[],"relativePath":"doc/sip023.md","filePath":"doc/sip023.md","lastUpdated":1692058814000}'),n={name:"doc/sip023.md"},i=a("",21),r=[i];function o(d,c,l,p,h,y){return s(),t("div",null,r)}const S=e(n,[["render",o]]);export{P as __pageData,S as default};
diff --git a/assets/doc_stream.md.f0d88fb6.js b/assets/doc_stream.md.ceb77f24.js
similarity index 98%
rename from assets/doc_stream.md.f0d88fb6.js
rename to assets/doc_stream.md.ceb77f24.js
index eca5d28..c6ad8c8 100644
--- a/assets/doc_stream.md.f0d88fb6.js
+++ b/assets/doc_stream.md.ceb77f24.js
@@ -1 +1 @@
-import{_ as t,c as e,o as a,R as r}from"./chunks/framework.bdd825cc.js";const u=JSON.parse('{"title":"Stream ciphers","description":"","frontmatter":{},"headers":[],"relativePath":"doc/stream.md","filePath":"doc/stream.md","lastUpdated":1691108507000}'),s={name:"doc/stream.md"},d=r('
Stream ciphers
Stream Encryption/Decryption
Stream_encrypt(key, IV, message) => ciphertext
Stream_decrypt(key, IV, ciphertext) => message
EVP_BytesToKey(3)
in OpenSSL. The detailed spec can be found here: https://wiki.openssl.org/index.php/Manual:EVP_BytesToKey(3)TCP
[IV][encrypted payload]
UDP
[IV][encrypted payload]
Historic stream ciphers
',18),i=[d];function c(n,o,p,l,h,m){return a(),e("div",null,i)}const g=t(s,[["render",c]]);export{u as __pageData,g as default};
+import{_ as t,c as e,o as a,R as r}from"./chunks/framework.bdd825cc.js";const u=JSON.parse('{"title":"Stream ciphers","description":"","frontmatter":{},"headers":[],"relativePath":"doc/stream.md","filePath":"doc/stream.md","lastUpdated":1692058814000}'),s={name:"doc/stream.md"},d=r('Name Key Size IV Length aes-128-ctr 16 16 aes-192-ctr 24 16 aes-256-ctr 32 16 aes-128-cfb 16 16 aes-192-cfb 24 16 aes-256-cfb 32 16 camellia-128-cfb 16 16 camellia-192-cfb 24 16 camellia-256-cfb 32 16 chacha20-ietf 32 12 bf-cfb 16 8 chacha20 32 8 salsa20 32 8 rc4-md5 16 16 Stream ciphers
Stream Encryption/Decryption
Stream_encrypt(key, IV, message) => ciphertext
Stream_decrypt(key, IV, ciphertext) => message
EVP_BytesToKey(3)
in OpenSSL. The detailed spec can be found here: https://wiki.openssl.org/index.php/Manual:EVP_BytesToKey(3)TCP
[IV][encrypted payload]
UDP
[IV][encrypted payload]
Historic stream ciphers
',18),i=[d];function c(n,o,p,l,h,m){return a(),e("div",null,i)}const g=t(s,[["render",c]]);export{u as __pageData,g as default};
diff --git a/assets/doc_stream.md.f0d88fb6.lean.js b/assets/doc_stream.md.ceb77f24.lean.js
similarity index 84%
rename from assets/doc_stream.md.f0d88fb6.lean.js
rename to assets/doc_stream.md.ceb77f24.lean.js
index a423721..46fcd6e 100644
--- a/assets/doc_stream.md.f0d88fb6.lean.js
+++ b/assets/doc_stream.md.ceb77f24.lean.js
@@ -1 +1 @@
-import{_ as t,c as e,o as a,R as r}from"./chunks/framework.bdd825cc.js";const u=JSON.parse('{"title":"Stream ciphers","description":"","frontmatter":{},"headers":[],"relativePath":"doc/stream.md","filePath":"doc/stream.md","lastUpdated":1691108507000}'),s={name:"doc/stream.md"},d=r("",18),i=[d];function c(n,o,p,l,h,m){return a(),e("div",null,i)}const g=t(s,[["render",c]]);export{u as __pageData,g as default};
+import{_ as t,c as e,o as a,R as r}from"./chunks/framework.bdd825cc.js";const u=JSON.parse('{"title":"Stream ciphers","description":"","frontmatter":{},"headers":[],"relativePath":"doc/stream.md","filePath":"doc/stream.md","lastUpdated":1692058814000}'),s={name:"doc/stream.md"},d=r("",18),i=[d];function c(n,o,p,l,h,m){return a(),e("div",null,i)}const g=t(s,[["render",c]]);export{u as __pageData,g as default};
diff --git a/assets/doc_what-is-shadowsocks.md.0cc6fd58.js b/assets/doc_what-is-shadowsocks.md.ac508dd6.js
similarity index 98%
rename from assets/doc_what-is-shadowsocks.md.0cc6fd58.js
rename to assets/doc_what-is-shadowsocks.md.ac508dd6.js
index 58befce..86d1406 100644
--- a/assets/doc_what-is-shadowsocks.md.0cc6fd58.js
+++ b/assets/doc_what-is-shadowsocks.md.ac508dd6.js
@@ -1 +1 @@
-import{_ as e,c as a,o as s,R as t}from"./chunks/framework.bdd825cc.js";const m=JSON.parse('{"title":"What is Shadowsocks?","description":"","frontmatter":{},"headers":[],"relativePath":"doc/what-is-shadowsocks.md","filePath":"doc/what-is-shadowsocks.md","lastUpdated":1691108507000}'),o={name:"doc/what-is-shadowsocks.md"},n=t('Name Key Size IV Length aes-128-ctr 16 16 aes-192-ctr 24 16 aes-256-ctr 32 16 aes-128-cfb 16 16 aes-192-cfb 24 16 aes-256-cfb 32 16 camellia-128-cfb 16 16 camellia-192-cfb 24 16 camellia-256-cfb 32 16 chacha20-ietf 32 12 bf-cfb 16 8 chacha20 32 8 salsa20 32 8 rc4-md5 16 16 What is Shadowsocks?
client <---> ss-local <--[encrypted]--> ss-remote <---> target
Addressing
[1-byte type][variable-length host][2-byte port]
0x01
: host is a 4-byte IPv4 address.0x03
: host is a variable length string, starting with a 1-byte length, followed by up to 255-byte domain name.0x04
: host is a 16-byte IPv6 address.TCP
[target address][payload]
UDP
[target address][payload]
[target address][payload]
What is Shadowsocks?
client <---> ss-local <--[encrypted]--> ss-remote <---> target
Addressing
[1-byte type][variable-length host][2-byte port]
0x01
: host is a 4-byte IPv4 address.0x03
: host is a variable length string, starting with a 1-byte length, followed by up to 255-byte domain name.0x04
: host is a 16-byte IPv6 address.TCP
[target address][payload]
UDP
[target address][payload]
[target address][payload]
What is SIP
How to submit a SIP?
When will a SIP be accepted?
What is SIP
How to submit a SIP?
When will a SIP be accepted?
sysctl -p
to reload the config at runtime.
A fast tunnel proxy that helps you bypass firewalls
Bleeding edge techniques using Asynchronous I/O and Event-driven programming.
Secured with industry level encryption algorithm. Flexible to support custom algorithms.
Optimized for mobile device and wireless network, with low CPU and bandwidth usage.
Available on most platforms, including Windows, Linux, Mac, Android, iOS, and OpenWRT.