#SS数据备忘
备忘笔记,任何错误均不负责。
- 明文内容
- 密文内容
- 通讯模型
##明文 SS 的明文数据结构上类似 socks5 协议中描述的数据结构。但是更加简单。SS省略了 socks5 的握手环节。客户端直接把要发的 TCP 包内容写给了服务器。
首先是TCP目的链接的位置,无非就是地址和端口。这里直接魔改 RFC1928 中的描述
+------+----------+----------+--------------+
| ATYP | DST.ADDR | DST.PORT | PACKAGE.DATA |
+------+----------+----------+--------------+
| 1 | Variable | 2 | Variable |
+------+----------+----------+--------------+
Where:
o ATYP address type of following address
o IP V4 address: X'01'
o DOMAINNAME: X'03'
o IP V6 address: X'04'
o DST.ADDR desired destination address
o DST.PORT desired destination port in network octet
order
o DST.PORT desired destination port in network octet
order
o PACKAGE.DATA raw TCP package data
举例而言,我在想向一台 IP 为 192.168.123.45 的机器的 2333 端口先发送一个内容为 0xAB 的数据包,再发送一个 0xCD 的数据包。 SS 需要加密的数据就是一个内容如下的数据流:
+------+------+------+------+------+------+------+------+------+------+
| HEX | 01 | C0 | A8 | 7B | 2D | 09 | 1D | AB | CD |
+------+------+------+------+------+------+------+------+------+------+
| DEX | 1 | 192 | 168 | 123 | 45 | 2333 | 171 | 205 |
+------+------+------+------+------+------+------+------+------+------+
##密文 SS用的都是基于对称加密算法的流加密。
所谓对称加密,就是加解密的双方共享相同的秘密信息。相对应的是非对称加密,例如 RSA,椭圆之类。各自优劣比较在此省略。 所谓流加密,就是说加密器的输入是一个长度不定数据流。相对应的是块加密,块加密要求加密的输入是一个指定长度数据,常见的有 AES 和 DES。
这里以 aes-128-cfb 为例讨论 SS 要传输的密文。
AES-128 是一个密钥长度为 128 bit 的块加密算法。 CFB 是一种把块加密器变成流加密器的算法。在 aes-128-cfb 正常工作以前,加解密的双发首先需要共享两个数据,一个是 IV(初始向量),一个是 AES-128 加密器用的 key(密钥)。
IV 通常是加密方随机生成,然后发送给解密方。
key 则是加解密双方依靠共享的 SS 链接信息来各自独立计算。具体的计算方法抽象来说就是 hash(method, password),这其中用到的 method 和 password 就是 config.json 中写的 method 和password。 具体的 hash 算法的实现说起来比较麻烦,略。
例如这里加密方需要发送的加密后数据是 0xEA7BADF00D, 随机生成的 IV 是 0x1234567890ABCDEF9876543210FEDCBA,key 是 0x43218765BA98FEDC13579ACE24680BDF 的话,实际会发送数据如下:
+------------+----+----+----+----+----+----+----+----+
| BYTE 0-7 | 12 | 34 | 56 | 78 | 90 | AB | CD | EF |
+------------+----+----+----+----+----+----+----+----+
| BYTE 8-15 | 98 | 76 | 54 | 32 | 10 | FE | DC | BA |
+------------+----+----+----+----+----+----+----+----+
| BYTE 16-20 | EA | 7B | AD | F0 | 0D |
+------------+----+----+----+----+----+
这里以两种不同的 TCP 通讯模型为例,描述 SS 的数据通讯模型。
为了行文方便,首先定义几个不同的符号:
- IV_x 表示加密器 x 所使用的初始向量;
- KEY_x 表示加密器 x 所使用的密钥;
- PT_a 表示一个叫 a 的未加密明文(Plain Text);
- CT_x_a 表示 PT_a 用加密器 x 加密后的密文(Cipher Text)。
- Head_x 表示连接信息用加密器 x 加密后的密文。所谓连接信息,指的是第一节关于明文的描述中 PACKAGE.DATA 之前的数据( 即为 :ATYP | DST.ADDR | DST.PORT)
首先一种是类似 HTTP 页面获取的模型。
客户端为了请求一个完整的 HTTP 页面,首先会与服务器建立一个 TCP 链接,请求 index.html 这个页面。然后会再发起若干个 TCP 链接,从服务器获取必须的 css 文件,png 文件等等。
假设这里有3个不同的 TCP session,时序如下图:
Client Server
| --- Start session 1 --> |
| --- PT_1.1 --> |
| <==== PT_1.2 ===== |
| --- End session 1 --> |
| |
| --- Start session 2 --> |
| --- Start session 3 --> |
| --- PT_2.1 --> |
| --- PT_3.1 --> |
| <==== PT_2.2 ===== |
| --- End session 2 --> |
| <==== PT_3.2 ===== |
| --- End session 3 --> |
与此对应的 SS 密文如下:
Client Server
| --- IV_a --> |
| --- Head_a --> |
| --- CT_a_1.1 --> |
| <==== IV_b ==== |
| <==== CT_b_1.2 ==== |
| |
| --- IV_c --> |
| --- Head_c --> |
| --- CT_c_2.1 --> |
| --- IV_d --> |
| --- Head_d --> |
| --- CT_d_3.1 --> |
| <==== IV_e ==== |
| <==== CT_e_2.2 ==== |
| <==== IV_f ==== |
| <==== CT_f_3.2 ==== |
另一种通讯模型是使用一个 TCP 长连接,反复在这个连接上进行对话。最常见的例子就是 ssh 链接。
这里将这个 TCP 链接抽象如下:
Client Server
| --- Start session 4 --> |
| |
| --- PT_4.1 --> |
| <==== PT_4.2 ===== |
| --- PT_4.3 --> |
| <==== PT_4.4 ===== |
| --- PT_4.5 --> |
| <==== PT_4.6 ===== |
| --- End session 4 --> |
与此对应的 SS 密文如下:
Client Server
| --- IV_g --> |
| --- Head_g --> |
| |
| --- CT_g_4.1 --> |
| <==== IV_h ==== |
| <==== CT_h_4.2 ==== |
| --- CT_g_4.3 --> |
| <==== CT_h_4.4 ==== |
| --- CT_g_4.5 --> |
| <==== CT_h_4.6 ==== |