1 个不稳定版本
0.1.0 | 2020 年 5 月 27 日 |
---|
#982 in 密码学
150KB
3.5K SLoC
Shadowrocks
掷石头到墙上
Shadowrocks 是一个使用纯 async/.await
Rust 编写的 shadowsocks
端口。目前它只做了基本功能:从本地 SOCKS5 服务器到远程服务器的隧道,并使用适当的加密。实现经过彻底测试,且与具有 --compatible-mode
的原始 Python 版本兼容。
可以在这里找到 shadowsocks
的官方 Rust 实现:这里。它具有更多功能。
如何运行
要启动端口 51980
的本地 SOCKS5 服务器,运行
cargo run -- -l 51980 -s 127.0.0.1 -p 51986 -k test-password
同时,通过运行以下命令启动远程 Shadow 服务器
cargo run -- --shadow -s 127.0.0.1 -p 51986 -k test-password
服务器地址 (-s
)、服务器端口 (-p
) 和密码 (-k
) 标志必须匹配。
也支持 JSON 配置文件 (-c
)。关于 SIP002 中的描述的 ss://
URL 将很快推出。
加密
支持五种加密类型
chacha20-ietf-poly1305
由 sodium 提供xchacha20-ietf-poly1305
由 sodium 提供aes-128-gcm
由 OpenSSL 提供aes-192-gcm
由 OpenSSL 提供aes-256-gcm
由 OpenSSL 提供
它们都是 AEAD 加密。
兼容性
在不兼容模式下,对 socks 服务器和 shadow 服务器之间的流量进行了几项更改。
- 主密钥使用
PBKDF2
生成,而不是原始版本中使用的PBKDF1
。主密钥仍然从密码生成。 - 子密钥通过使用
HKDF
和SHA256
生成,而不是不再安全的SHA1
,输入到HKDF
的密钥仍然是主密钥。 - 在加密握手过程中,用于加密输出流量的盐由代理服务器指定,而代理服务器使用的盐由 socks 服务器指定。这与原始版本相反,原始版本中每个服务器决定自己的盐。
第3项有助于防御重放攻击。如果我们合理地假设生成的盐每次都不同,那么两个服务器必须为每个新的连接重新加密流量。攻击者将需要为会话生成不同的子密钥,而没有主密钥是无法做到的。
在不兼容模式下,shadowrocks
的行为与原始版本相同。
功能
- TCP隧道
- 集成 Clippy
- 基准测试
- 集成测试
- 模块级文档
- 详细记录
src/crypto
中的代码 - 可选 fake-tcp 的 UDP 隧道
- 兼容模式下的重放攻击缓解
- 非兼容模式下的重放攻击缓解
- 本地混淆
- 管理器 API 以动态创建服务器
-
ss://
URL 和 JSON 配置文件
加密依赖项
同时使用 ring
模块(BoringSSL)和 openssl
模块。这两个模块的功能在很大程度上重叠。ring
最初被用作对openssl
的参考点和合理性检查,当作者不熟悉shadowsocks
中使用的加密时。
ring
和 openssl
功能表
功能 | ring |
openssl |
---|---|---|
PBKDF1 |
✅ | |
PBKDF2 |
✅ | ✅ |
HKDF-SHA1 |
✅ | ✅ |
HKDF-SHA256 |
✅ | ✅ |
AES-128-GCM |
✅ | ✅ |
AES-192-GCM |
✅ | |
AES-256-GCM |
✅ | ✅ |
HKDF-SHA1
支持 最近 被添加到 ring
。
可以通过禁用功能 ring-crypto
来禁用 ring
模块。目前无法完全禁用 openssl
模块。
改进
- 减少加密/解密过程中的内存分配。
当前实现为每个连接执行许多小内存分配。例如,为了从 socks 服务器向远程代理服务器发送 SOCKS 5 地址,按照以下过程进行。
- 将 SOCKS 5 地址转换为字节。
- 将数据包长度转换为字节(
x
字节,x = 2
)。 - 将nonce转换为字节(4字节)。
- OpenSSL 加密对象。
- 数据包长度的密文(
x
字节,x = 2
)。 - 加密标签(16字节)。
- 密文和标签的连接(18字节)。
- 对于具有不同
x
的 SOCKS5 地址,重复 2-7 步。
总结来说,每个数据包有13个分配。每次加密需要6个分配,而每个数据包我们需要加密两次:一次用于数据包长度,一次用于实际信息。
读取过程类似。
- 数据包长度的密文。
- 加密标签
- 将nonce转换为字节
- OpenSSL 加密对象。
- 数据包长度明文。
- 对数据包内容重复1-5步骤。
对于“无标签密文”部分,我们省了一步。尽管如此,这仍然很糟糕。
依赖项
~31MB
~367K SLoC