SS通讯步骤
目前在写一个Socks5转SS的工具(某些奇怪需求需要), 在互联网上翻了几个网站并没有详细说明SS通讯步骤. 所以在这记录下.
密码初始化
本文章aes-256-cfb
加密来说明, 当使用AES时需要提供Key
与IV
(初始化向量). 其中IV
类似于给hash加盐, 不过这个盐是基于上一个数据块加密后的出来的盐. 那为啥还需要提供IV
呢?因为第一次用的时候没上一块数据只能自己指定一个.
SS
生成Key
与IV
是基于用户指定的密码来生成的, 以下为TypeScript基于密码生成Key
与IV
代码:
function generateKeyIVByPassword(passwordString: string, keyLength: number, ivLength: number): any {
var password = new Buffer(passwordString, "binary");
var hashBuffers: Array<Buffer> = [];
for (var dataCount = 0, loopCount = 0; dataCount < keyLength + ivLength; loopCount++) {
var data: any = password;
if (loopCount > 0) {
data = Buffer.concat([hashBuffers[loopCount - 1], password]);
}
var md5 = crypto.createHash("md5");
var md5Buffer = md5.update(data).digest();
hashBuffers.push(md5Buffer);
dataCount += md5Buffer.length;
}
var hashBuffer: Buffer = Buffer.concat(hashBuffers);
return {
key: hashBuffer.slice(0, keyLength),
iv: hashBuffer.slice(keyLength, keyLength + ivLength)
};
}
从上述代码中可以得知SS
作者先将用户指定的密码迭代MD5多次; 其结束条件是迭代多次的MD5结果长度相加, 如果长度大于加密算法
所需Key长度
+ IV长度
则退出循环. 最后将MD5 Hash结果截断来获得Key
与IV
.
通讯过程(TCP过程)
当客户端连接至服务端后会直接发送 客户端IV
+ 已被加密的Socks5头 + TCP数据
.
IV交换
当Client
连接后, Client
发送的第一个数据前N个字节
(取决于加密算法)是AESIV
用于来解密来自Client
的数据.
然后Server
发送Client
的第一个数据也是类似. 其结构图如下:
注意!
SS
中这样交换IV
是不安全做法.
通讯
SS
省略了Socks5
协商过程直接进入通讯过程. Socks5
通讯需要客户端提供 目标IP或域名 + 端口. 当客户端提供完成之后服务端会连接至目标IP并返回是否连接成功; 如果连接成功就能够直接通讯了.
格式如下:
上述说过SS
省略了协商过程, 所以这里Socks5
请求也是缩水的. 其把前3个字节
砍掉了, 也就是说Client
只会发来ATYP
, DST ADDR
, DST PROT
. 当连接至DST ADDR
后DST ADDR
发送的数据加密发送给Client
, Client
发送的数据解密发送给DST ADDR
. 这样SS
就完成了通讯.
参考资料
- SS C#服务端以及客户端
- Socks协议 - 维基百科
- 生成加密和解密的密钥 - MSDN