Skip to content

Instantly share code, notes, and snippets.

@finas
Forked from srayuws/gist:738e2ce44768f84fe6ea
Last active May 7, 2019 03:49
Show Gist options
  • Save finas/7b5deff40fc751129a0b872c28add668 to your computer and use it in GitHub Desktop.
Save finas/7b5deff40fc751129a0b872c28add668 to your computer and use it in GitHub Desktop.
SS协议

#SS数据备忘

备忘笔记,任何错误均不负责。

  1. 明文内容
  2. 密文内容
  3. 通讯模型

##明文 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)

多个 TCP 链接

首先一种是类似 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 长链接

另一种通讯模型是使用一个 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 ==== |
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment