加密算法可选

This commit is contained in:
lubeilin
2023-09-27 19:51:23 +08:00
parent 40cbd2e26b
commit bd61cad7b6
9 changed files with 241 additions and 48 deletions
+35 -1
View File
@@ -3,7 +3,9 @@
A virtual network tool (VPN) A virtual network tool (VPN)
将不同网络下的多个设备虚拟到一个局域网下 将不同网络下的多个设备虚拟到一个局域网下
### vnt-cli参数详解 [参数说明](https://github.com/lbl8603/vnt/blob/main/vnt-cli/README.md) ### vnt-cli参数详解 [参数说明](https://github.com/lbl8603/vnt/blob/main/vnt-cli/README.md)
### 快速使用: ### 快速使用:
1. 指定一个token,在多台设备上运行该程序,例如: 1. 指定一个token,在多台设备上运行该程序,例如:
@@ -61,8 +63,28 @@ A virtual network tool (VPN)
前提条件:安装rust编译环境([install rust](https://www.rust-lang.org/zh-CN/tools/install)) 前提条件:安装rust编译环境([install rust](https://www.rust-lang.org/zh-CN/tools/install))
```
到项目根目录下执行 cargo build -p vnt-cli 到项目根目录下执行 cargo build -p vnt-cli
也可按需编译,将得到更小的二进制文件,使用--no-default-features排除默认features
cargo build -p vnt-cli --no-default-features --features raw
```
features说明
| feature | 说明 |
|------------------|----------------------|
| raw | 默认 |
| openssl | 使用openssl中的aes_ecb算法 |
| openssl-vendored | 从源码编译openssl |
| ring-cipher | 使用ring中的aes_gcm算法 |
| aes_cbc | 支持aes_cbc加密 |
| aes_ecb | 支持aes_ecb加密 |
| aes_gcm | 支持aes_gcm加密 |
| aes_ecb | 支持aes_ecb加密 |
| server_encrypt | 支持服务端加密 |
### 支持平台 ### 支持平台
- Mac - Mac
@@ -86,7 +108,9 @@ A virtual network tool (VPN)
- p2p组播/广播 - p2p组播/广播
- 客户端数据加密 - 客户端数据加密
- 服务端数据加密 - 服务端数据加密
### 结构 ### 结构
<details> <summary>展开</summary> <details> <summary>展开</summary>
<pre> <pre>
@@ -121,6 +145,7 @@ A virtual network tool (VPN)
- 支持Ipv6(1.2.2已支持客户端之间的ipv6,待支持客户端和服务端之间的ipv6通信) - 支持Ipv6(1.2.2已支持客户端之间的ipv6,待支持客户端和服务端之间的ipv6通信)
### 常见问题 ### 常见问题
<details> <summary>展开</summary> <details> <summary>展开</summary>
#### 问题1: 设置网络地址失败 #### 问题1: 设置网络地址失败
@@ -138,26 +163,35 @@ vnt默认使用10.26.0.0/24网段,和本地网络适配器的ip冲突
#### 问题2: windows系统上wintun.dll加载失败 #### 问题2: windows系统上wintun.dll加载失败
##### 可能原因: ##### 可能原因:
没有下载wintun.dll 或者使用的wintun.dll有问题 没有下载wintun.dll 或者使用的wintun.dll有问题
##### 解决方法: ##### 解决方法:
1. 下载最新版的wintun.dll [下载链接](https://www.wintun.net/builds/wintun-0.14.1.zip) 1. 下载最新版的wintun.dll [下载链接](https://www.wintun.net/builds/wintun-0.14.1.zip)
2. 解压后找到对应架构的目录,通常是amd64 2. 解压后找到对应架构的目录,通常是amd64
3. 将对应的wintun.dll放到和vnt-cli同目录下(或者放到C盘Windows目录下) 3. 将对应的wintun.dll放到和vnt-cli同目录下(或者放到C盘Windows目录下)
4. 再次启动vnt-cli 4. 再次启动vnt-cli
#### 问题3: 丢包严重,或是不能正常组网通信 #### 问题3: 丢包严重,或是不能正常组网通信
##### 可能原因: ##### 可能原因:
某些宽带下(比如广电宽带)UDP丢包严重 某些宽带下(比如广电宽带)UDP丢包严重
##### 解决方法: ##### 解决方法:
1. 使用TCP模式中继转发(vnt-cli增加--tcp参数) 1. 使用TCP模式中继转发(vnt-cli增加--tcp参数)
2. 如果p2p后效果很差,可以选择禁用p2p(vnt-cli增加--relay参数) 2. 如果p2p后效果很差,可以选择禁用p2p(vnt-cli增加--relay参数)
</details> </details>
### 交流群 ### 交流群
QQ:1034868233 QQ:1034868233
### 其他 ### 其他
可使用社区小伙伴搭建的中继服务器 可使用社区小伙伴搭建的中继服务器
1. -s vnt.8443.eu.org:29871 1. -s vnt.8443.eu.org:29871
+9 -4
View File
@@ -6,13 +6,13 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
vnt = { path = "../vnt", package = "vnt", optional = true } vnt = { path = "../vnt", package = "vnt",default-features = false, optional = true }
common = { path = "../common" } common = { path = "../common" }
tokio = { version = "1.32.0", features = ["full"] } tokio = { version = "1.32.0", features = ["full"] }
getopts = "0.2.21" getopts = "0.2.21"
console = "0.15.2" console = "0.15.2"
os_info = "3.7.0" os_info = "3.7.0"
dirs = "4.0.0" dirs = "5.0.1"
serde = "1.0" serde = "1.0"
serde_json = "1.0.94" serde_json = "1.0.94"
serde_yaml = "0.9.25" serde_yaml = "0.9.25"
@@ -31,11 +31,16 @@ sudo = "0.6.0"
winapi = { version = "0.3.9", features = ["handleapi", "processthreadsapi", "winnt", "securitybaseapi", "impl-default"] } winapi = { version = "0.3.9", features = ["handleapi", "processthreadsapi", "winnt", "securitybaseapi", "impl-default"] }
[features] [features]
default = ["vnt"] default = ["server_encrypt","aes_gcm","aes_cbc","aes_ecb","sm4_cbc"]
raw=["vnt"]
openssl = ["vnt/openssl"] openssl = ["vnt/openssl"]
openssl-vendored = ["vnt/openssl-vendored"] openssl-vendored = ["vnt/openssl-vendored"]
ring-cipher = ["vnt/ring-cipher"] ring-cipher = ["vnt/ring-cipher"]
aes_cbc=["vnt/aes_cbc"]
aes_ecb=["vnt/aes_ecb"]
sm4_cbc=["vnt/sm4_cbc"]
aes_gcm=["vnt/aes_gcm"]
server_encrypt=["vnt/server_encrypt"]
[build-dependencies] [build-dependencies]
embed-manifest = "1.4.0" embed-manifest = "1.4.0"
+51 -3
View File
@@ -179,6 +179,13 @@ fn main() {
}; };
let password: Option<String> = matches.opt_get("w").unwrap(); let password: Option<String> = matches.opt_get("w").unwrap();
let server_encrypt = matches.opt_present("W"); let server_encrypt = matches.opt_present("W");
#[cfg(not(feature = "server_encrypt"))]
{
if server_encrypt {
println!("Server encryption not supported");
return;
}
}
let simulate_multicast = matches.opt_present("m"); let simulate_multicast = matches.opt_present("m");
let mtu: Option<String> = matches.opt_get("u").unwrap(); let mtu: Option<String> = matches.opt_get("u").unwrap();
let mtu = if let Some(mtu) = mtu { let mtu = if let Some(mtu) = mtu {
@@ -213,7 +220,31 @@ fn main() {
} }
let cipher_model = match matches.opt_get::<CipherModel>("model") { let cipher_model = match matches.opt_get::<CipherModel>("model") {
Ok(model) => model.unwrap_or(CipherModel::AesGcm), Ok(model) => {
#[cfg(not(any(
feature = "aes_gcm",
feature = "server_encrypt",
feature = "aes_cbc",
feature = "aes_ecb",
feature = "sm4_cbc"
)))]
{
if password.is_some() && model.is_none() {
println!("Encryption not supported");
return;
}
}
#[cfg(not(any(feature = "aes_gcm", feature = "server_encrypt")))]
{
if password.is_some() && model.is_none() {
println!("'--model ' undefined");
return;
}
model.unwrap_or(CipherModel::None)
}
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
model.unwrap_or(CipherModel::AesGcm)
}
Err(e) => { Err(e) => {
println!("'--model ' invalid,{}", e); println!("'--model ' invalid,{}", e);
return; return;
@@ -452,7 +483,19 @@ fn print_usage(program: &str, _opts: Options) {
println!(" -i <in-ip> 配置点对网(IP代理)时使用,-i 192.168.0.0/24,10.26.0.3表示允许接收网段192.168.0.0/24的数据"); println!(" -i <in-ip> 配置点对网(IP代理)时使用,-i 192.168.0.0/24,10.26.0.3表示允许接收网段192.168.0.0/24的数据");
println!(" 并转发到10.26.0.3,可指定多个网段"); println!(" 并转发到10.26.0.3,可指定多个网段");
println!(" -o <out-ip> 配置点对网时使用,-o 192.168.0.0/24表示允许将数据转发到192.168.0.0/24,可指定多个网段"); println!(" -o <out-ip> 配置点对网时使用,-o 192.168.0.0/24表示允许将数据转发到192.168.0.0/24,可指定多个网段");
println!(" -w <password> 使用该密码生成的密钥对客户端数据进行加密,并且服务端无法解密,使用相同密码的客户端才能通信"); let mut enums = String::new();
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
enums.push_str("/aes_gcm");
#[cfg(feature = "aes_cbc")]
enums.push_str("/aes_cbc");
#[cfg(feature = "aes_ecb")]
enums.push_str("/aes_ecb");
#[cfg(feature = "sm4_cbc")]
enums.push_str("/sm4_cbc");
if !enums.is_empty() {
println!(" -w <password> 使用该密码生成的密钥对客户端数据进行加密,并且服务端无法解密,使用相同密码的客户端才能通信");
}
#[cfg(feature = "server_encrypt")]
println!(" -W 加密当前客户端和服务端通信的数据,请留意服务端指纹是否正确"); println!(" -W 加密当前客户端和服务端通信的数据,请留意服务端指纹是否正确");
println!(" -m 模拟组播,默认情况下组播数据会被当作广播发送,开启后会模拟真实组播的数据发送"); println!(" -m 模拟组播,默认情况下组播数据会被当作广播发送,开启后会模拟真实组播的数据发送");
println!(" -u <mtu> 自定义mtu(不加密默认为1450,加密默认为1410)"); println!(" -u <mtu> 自定义mtu(不加密默认为1450,加密默认为1410)");
@@ -462,7 +505,12 @@ fn print_usage(program: &str, _opts: Options) {
println!(" --ip <ip> 指定虚拟ip,指定的ip不能和其他设备重复,必须有效并且在服务端所属网段下,默认情况由服务端分配"); println!(" --ip <ip> 指定虚拟ip,指定的ip不能和其他设备重复,必须有效并且在服务端所属网段下,默认情况由服务端分配");
println!(" --relay 仅使用服务器转发,不使用p2p,默认情况允许使用p2p"); println!(" --relay 仅使用服务器转发,不使用p2p,默认情况允许使用p2p");
println!(" --par <parallel> 任务并行度(必须为正整数),默认值为1"); println!(" --par <parallel> 任务并行度(必须为正整数),默认值为1");
println!(" --model <model> 加密模式(默认aes_gcm),可选值aes_gcm/aes_cbc/aes_ecb/sm4_cbc"); if !enums.is_empty() {
println!(
" --model <model> 加密模式(默认aes_gcm),可选值{}",
&enums[1..]
);
}
println!(" --finger 增加数据指纹校验,可增加安全性,如果服务端开启指纹校验,则客户端也必须开启"); println!(" --finger 增加数据指纹校验,可增加安全性,如果服务端开启指纹校验,则客户端也必须开启");
println!(" --punch <punch> 取值ipv4/ipv6ipv4表示仅使用ipv4打洞"); println!(" --punch <punch> 取值ipv4/ipv6ipv4表示仅使用ipv4打洞");
println!(" --port <port> 取值0~65535,指定本地监听的端口,默认取随机端口"); println!(" --port <port> 取值0~65535,指定本地监听的端口,默认取随机端口");
+12 -8
View File
@@ -20,16 +20,16 @@ thiserror = "1.0.37"
protobuf = "3.2.0" protobuf = "3.2.0"
socket2 = { version = "0.5.2", features = ["all"] } socket2 = { version = "0.5.2", features = ["all"] }
tokio = { version = "1.32.0", features = ["full"] } tokio = { version = "1.32.0", features = ["full"] }
aes-gcm = { version = "0.10.2" } aes-gcm = { version = "0.10.2",optional = true }
ring = { version = "0.16.20", optional = true } ring = { version = "0.16.20", optional = true }
cbc = "0.1.2" cbc = {version = "0.1.2",optional = true}
ecb = "0.1.2" ecb = {version = "0.1.2",optional = true}
aes = "0.8.3" aes = "0.8.3"
stun-format = { version = "1.0.1", features = ["fmt", "rfc3489"] } stun-format = { version = "1.0.1", features = ["fmt", "rfc3489"] }
rsa = { version = "0.7.2", features = [] } rsa = { version = "0.7.2", features = [] ,optional = true}
spki = { version = "0.6.0", features = ["fingerprint", "alloc"] } spki = { version = "0.6.0", features = ["fingerprint", "alloc"] ,optional = true}
openssl-sys = { git = "https://github.com/lbl8603/rust-openssl" ,optional = true} openssl-sys = { git = "https://github.com/lbl8603/rust-openssl" ,optional = true}
libsm = {git="https://github.com/lbl8603/libsm"} libsm = {git="https://github.com/lbl8603/libsm" ,optional = true}
[target.'cfg(any(target_os = "linux",target_os = "macos"))'.dependencies] [target.'cfg(any(target_os = "linux",target_os = "macos"))'.dependencies]
tun = { path = "./rust-tun" } tun = { path = "./rust-tun" }
@@ -44,10 +44,14 @@ protobuf-codegen = "3.2.0"
protoc-bin-vendored = "3.0.0" protoc-bin-vendored = "3.0.0"
[features] [features]
default = [] default = ["server_encrypt","aes_gcm","aes_cbc","aes_ecb","sm4_cbc"]
openssl = ["openssl-sys"] openssl = ["openssl-sys"]
# 从源码编译 # 从源码编译
openssl-vendored = ["openssl-sys/vendored"] openssl-vendored = ["openssl-sys/vendored"]
ring-cipher = ["ring"] ring-cipher = ["ring"]
aes_cbc=["cbc"]
aes_ecb=["ecb"]
sm4_cbc=["libsm"]
aes_gcm=["aes-gcm","ring"]
server_encrypt =["rsa","spki"]
+84 -14
View File
@@ -1,25 +1,37 @@
#[cfg(feature = "aes_ecb")]
#[cfg(not(any(feature = "openssl-vendored", feature = "openssl")))] #[cfg(not(any(feature = "openssl-vendored", feature = "openssl")))]
use crate::cipher::aes_ecb::AesEcbCipher; use crate::cipher::aes_ecb::AesEcbCipher;
#[cfg(feature = "aes_cbc")]
use crate::cipher::aes_cbc::AesCbcCipher;
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
#[cfg(not(feature = "ring-cipher"))] #[cfg(not(feature = "ring-cipher"))]
use crate::cipher::aes_gcm_cipher::AesGcmCipher; use crate::cipher::aes_gcm_cipher::AesGcmCipher;
#[cfg(feature = "aes_ecb")]
#[cfg(any(feature = "openssl-vendored", feature = "openssl"))] #[cfg(any(feature = "openssl-vendored", feature = "openssl"))]
use crate::cipher::openssl_aes_ecb::AesEcbCipher; use crate::cipher::openssl_aes_ecb::AesEcbCipher;
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
#[cfg(feature = "ring-cipher")] #[cfg(feature = "ring-cipher")]
use crate::cipher::ring_aes_gcm_cipher::AesGcmCipher; use crate::cipher::ring_aes_gcm_cipher::AesGcmCipher;
#[cfg(feature = "sm4_cbc")]
use crate::cipher::sm4_cbc::Sm4CbcCipher; use crate::cipher::sm4_cbc::Sm4CbcCipher;
use crate::cipher::{aes_cbc, Finger}; use crate::cipher::Finger;
use crate::protocol::NetPacket; use crate::protocol::NetPacket;
use aes_cbc::AesCbcCipher;
use sha2::Digest; use sha2::Digest;
use std::io; use std::io;
use std::str::FromStr; use std::str::FromStr;
#[derive(Copy, Clone, Eq, PartialEq, Debug)] #[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum CipherModel { pub enum CipherModel {
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
AesGcm, AesGcm,
#[cfg(feature = "aes_cbc")]
AesCbc, AesCbc,
#[cfg(feature = "aes_ecb")]
AesEcb, AesEcb,
#[cfg(feature = "sm4_cbc")]
Sm4Cbc, Sm4Cbc,
None,
} }
impl FromStr for CipherModel { impl FromStr for CipherModel {
@@ -27,20 +39,44 @@ impl FromStr for CipherModel {
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_lowercase().trim() { match s.to_lowercase().trim() {
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
"aes_gcm" => Ok(CipherModel::AesGcm), "aes_gcm" => Ok(CipherModel::AesGcm),
#[cfg(feature = "aes_cbc")]
"aes_cbc" => Ok(CipherModel::AesCbc), "aes_cbc" => Ok(CipherModel::AesCbc),
#[cfg(feature = "aes_ecb")]
"aes_ecb" => Ok(CipherModel::AesEcb), "aes_ecb" => Ok(CipherModel::AesEcb),
#[cfg(feature = "sm4_cbc")]
"sm4_cbc" => Ok(CipherModel::Sm4Cbc), "sm4_cbc" => Ok(CipherModel::Sm4Cbc),
_ => Err(format!("not match '{}', enum:aes_gcm/aes_cbc/aes_ecb", s)), _ => {
let mut enums = String::new();
#[cfg(feature = "aes_gcm")]
enums.push_str("/aes_gcm");
#[cfg(feature = "aes_cbc")]
enums.push_str("/aes_cbc");
#[cfg(feature = "aes_ecb")]
enums.push_str("/aes_ecb");
#[cfg(feature = "sm4_cbc")]
enums.push_str("/sm4_cbc");
let str = if enums.is_empty() {
"no encrypt"
} else {
&enums[1..]
};
Err(format!("not match '{}', enum:{}", s, str))
}
} }
} }
} }
#[derive(Clone)] #[derive(Clone)]
pub enum Cipher { pub enum Cipher {
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
AesGcm((AesGcmCipher, Vec<u8>)), AesGcm((AesGcmCipher, Vec<u8>)),
#[cfg(feature = "aes_cbc")]
AesCbc(AesCbcCipher), AesCbc(AesCbcCipher),
#[cfg(feature = "aes_ecb")]
AesEcb(AesEcbCipher), AesEcb(AesEcbCipher),
#[cfg(feature = "sm4_cbc")]
Sm4Cbc(Sm4CbcCipher), Sm4Cbc(Sm4CbcCipher),
None, None,
} }
@@ -57,6 +93,7 @@ impl Cipher {
hasher.update(password.as_bytes()); hasher.update(password.as_bytes());
let key: [u8; 32] = hasher.finalize().into(); let key: [u8; 32] = hasher.finalize().into();
match model { match model {
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
CipherModel::AesGcm => { CipherModel::AesGcm => {
if password.len() < 8 { if password.len() < 8 {
let aes = AesGcmCipher::new_128(key[..16].try_into().unwrap(), finger); let aes = AesGcmCipher::new_128(key[..16].try_into().unwrap(), finger);
@@ -66,6 +103,7 @@ impl Cipher {
Cipher::AesGcm((aes, key.to_vec())) Cipher::AesGcm((aes, key.to_vec()))
} }
} }
#[cfg(feature = "aes_cbc")]
CipherModel::AesCbc => { CipherModel::AesCbc => {
if password.len() < 8 { if password.len() < 8 {
let aes = AesCbcCipher::new_128(key[..16].try_into().unwrap(), finger); let aes = AesCbcCipher::new_128(key[..16].try_into().unwrap(), finger);
@@ -75,6 +113,7 @@ impl Cipher {
Cipher::AesCbc(aes) Cipher::AesCbc(aes)
} }
} }
#[cfg(feature = "aes_ecb")]
CipherModel::AesEcb => { CipherModel::AesEcb => {
if password.len() < 8 { if password.len() < 8 {
let aes = AesEcbCipher::new_128(key[..16].try_into().unwrap(), finger); let aes = AesEcbCipher::new_128(key[..16].try_into().unwrap(), finger);
@@ -84,10 +123,12 @@ impl Cipher {
Cipher::AesEcb(aes) Cipher::AesEcb(aes)
} }
} }
#[cfg(feature = "sm4_cbc")]
CipherModel::Sm4Cbc => { CipherModel::Sm4Cbc => {
let aes = Sm4CbcCipher::new_128(key[..16].try_into().unwrap(), finger); let aes = Sm4CbcCipher::new_128(key[..16].try_into().unwrap(), finger);
Cipher::Sm4Cbc(aes) Cipher::Sm4Cbc(aes)
} }
CipherModel::None => Cipher::None,
} }
} else { } else {
Cipher::None Cipher::None
@@ -96,10 +137,12 @@ impl Cipher {
pub fn new_key(key: [u8; 32], token: String) -> io::Result<Self> { pub fn new_key(key: [u8; 32], token: String) -> io::Result<Self> {
let finger = Some(Finger::new(&token)); let finger = Some(Finger::new(&token));
match key.len() { match key.len() {
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
16 => { 16 => {
let aes = AesGcmCipher::new_128(key[..16].try_into().unwrap(), finger); let aes = AesGcmCipher::new_128(key[..16].try_into().unwrap(), finger);
Ok(Cipher::AesGcm((aes, key[..16].to_vec()))) Ok(Cipher::AesGcm((aes, key[..16].to_vec())))
} }
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
32 => { 32 => {
let aes = AesGcmCipher::new_256(key, finger); let aes = AesGcmCipher::new_256(key, finger);
Ok(Cipher::AesGcm((aes, key.to_vec()))) Ok(Cipher::AesGcm((aes, key.to_vec())))
@@ -112,9 +155,13 @@ impl Cipher {
net_packet: &mut NetPacket<B>, net_packet: &mut NetPacket<B>,
) -> io::Result<()> { ) -> io::Result<()> {
match self { match self {
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
Cipher::AesGcm((aes_gcm, _)) => aes_gcm.decrypt_ipv4(net_packet), Cipher::AesGcm((aes_gcm, _)) => aes_gcm.decrypt_ipv4(net_packet),
#[cfg(feature = "aes_cbc")]
Cipher::AesCbc(aes_cbc) => aes_cbc.decrypt_ipv4(net_packet), Cipher::AesCbc(aes_cbc) => aes_cbc.decrypt_ipv4(net_packet),
#[cfg(feature = "aes_ecb")]
Cipher::AesEcb(aes_ecb) => aes_ecb.decrypt_ipv4(net_packet), Cipher::AesEcb(aes_ecb) => aes_ecb.decrypt_ipv4(net_packet),
#[cfg(feature = "sm4_cbc")]
Cipher::Sm4Cbc(sm4_cbc) => sm4_cbc.decrypt_ipv4(net_packet), Cipher::Sm4Cbc(sm4_cbc) => sm4_cbc.decrypt_ipv4(net_packet),
Cipher::None => { Cipher::None => {
if net_packet.is_encrypt() { if net_packet.is_encrypt() {
@@ -129,32 +176,55 @@ impl Cipher {
net_packet: &mut NetPacket<B>, net_packet: &mut NetPacket<B>,
) -> io::Result<()> { ) -> io::Result<()> {
match self { match self {
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
Cipher::AesGcm((aes_gcm, _)) => aes_gcm.encrypt_ipv4(net_packet), Cipher::AesGcm((aes_gcm, _)) => aes_gcm.encrypt_ipv4(net_packet),
#[cfg(feature = "aes_cbc")]
Cipher::AesCbc(aes_cbc) => aes_cbc.encrypt_ipv4(net_packet), Cipher::AesCbc(aes_cbc) => aes_cbc.encrypt_ipv4(net_packet),
#[cfg(feature = "aes_ecb")]
Cipher::AesEcb(aes_ecb) => aes_ecb.encrypt_ipv4(net_packet), Cipher::AesEcb(aes_ecb) => aes_ecb.encrypt_ipv4(net_packet),
#[cfg(feature = "sm4_cbc")]
Cipher::Sm4Cbc(sm4_cbc) => sm4_cbc.encrypt_ipv4(net_packet), Cipher::Sm4Cbc(sm4_cbc) => sm4_cbc.encrypt_ipv4(net_packet),
Cipher::None => Ok(()), Cipher::None => Ok(()),
} }
} }
pub fn check_finger<B: AsRef<[u8]>>(&self, net_packet: &NetPacket<B>) -> io::Result<()> { pub fn check_finger<B: AsRef<[u8]>>(&self, net_packet: &NetPacket<B>) -> io::Result<()> {
let finger = match self { match self {
Cipher::AesGcm((aes_gcm, _)) => aes_gcm.finger.as_ref(), #[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
Cipher::AesCbc(aes_cbc) => aes_cbc.finger.as_ref(), Cipher::AesGcm((aes_gcm, _)) => aes_gcm
Cipher::AesEcb(aes_ecb) => aes_ecb.finger.as_ref(), .finger
Cipher::Sm4Cbc(sm4_cbc) => sm4_cbc.finger.as_ref(), .as_ref()
Cipher::None => None, .map(|f| f.check_finger(net_packet))
}; .unwrap_or(Ok(())),
if let Some(finger) = finger { #[cfg(feature = "aes_cbc")]
finger.check_finger(net_packet) Cipher::AesCbc(aes_cbc) => aes_cbc
} else { .finger
Ok(()) .as_ref()
.map(|f| f.check_finger(net_packet))
.unwrap_or(Ok(())),
#[cfg(feature = "aes_ecb")]
Cipher::AesEcb(aes_ecb) => aes_ecb
.finger
.as_ref()
.map(|f| f.check_finger(net_packet))
.unwrap_or(Ok(())),
#[cfg(feature = "sm4_cbc")]
Cipher::Sm4Cbc(sm4_cbc) => sm4_cbc
.finger
.as_ref()
.map(|f| f.check_finger(net_packet))
.unwrap_or(Ok(())),
Cipher::None => Ok(()),
} }
} }
pub fn key(&self) -> Option<&[u8]> { pub fn key(&self) -> Option<&[u8]> {
match self { match self {
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
Cipher::AesGcm((_, key)) => Some(key), Cipher::AesGcm((_, key)) => Some(key),
#[cfg(feature = "aes_cbc")]
Cipher::AesCbc(aes_cbc) => Some(aes_cbc.key()), Cipher::AesCbc(aes_cbc) => Some(aes_cbc.key()),
#[cfg(feature = "aes_ecb")]
Cipher::AesEcb(aes_ecb) => Some(aes_ecb.key()), Cipher::AesEcb(aes_ecb) => Some(aes_ecb.key()),
#[cfg(feature = "sm4_cbc")]
Cipher::Sm4Cbc(sm4_cbc) => Some(sm4_cbc.key()), Cipher::Sm4Cbc(sm4_cbc) => Some(sm4_cbc.key()),
Cipher::None => None, Cipher::None => None,
} }
+8 -3
View File
@@ -1,16 +1,21 @@
#[cfg(feature = "aes_cbc")]
mod aes_cbc; mod aes_cbc;
#[cfg(feature = "aes_ecb")]
#[cfg(not(any(feature = "openssl-vendored", feature = "openssl")))] #[cfg(not(any(feature = "openssl-vendored", feature = "openssl")))]
mod aes_ecb; mod aes_ecb;
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
#[cfg(not(feature = "ring-cipher"))] #[cfg(not(feature = "ring-cipher"))]
mod aes_gcm_cipher; mod aes_gcm_cipher;
mod cipher; mod cipher;
mod finger; mod finger;
#[cfg(feature = "aes_ecb")]
#[cfg(any(feature = "openssl-vendored", feature = "openssl"))]
mod openssl_aes_ecb;
#[cfg(any(feature = "aes_gcm", feature = "server_encrypt"))]
#[cfg(feature = "ring-cipher")] #[cfg(feature = "ring-cipher")]
mod ring_aes_gcm_cipher; mod ring_aes_gcm_cipher;
mod rsa_cipher; mod rsa_cipher;
#[cfg(feature = "sm4_cbc")]
#[cfg(any(feature = "openssl-vendored", feature = "openssl"))]
mod openssl_aes_ecb;
mod sm4_cbc; mod sm4_cbc;
pub use cipher::Cipher; pub use cipher::Cipher;
pub use cipher::CipherModel; pub use cipher::CipherModel;
+33 -7
View File
@@ -1,23 +1,32 @@
use crate::protocol::body::{RsaSecretBody, RSA_ENCRYPTION_RESERVED};
use crate::protocol::NetPacket; use crate::protocol::NetPacket;
use rand::Rng;
use rsa::pkcs8::der::Decode;
use rsa::{PublicKey, RsaPublicKey};
use sha2::Digest;
use spki::{DecodePublicKey, EncodePublicKey};
use std::io; use std::io;
#[cfg(feature = "server_encrypt")]
use crate::protocol::body::{RsaSecretBody, RSA_ENCRYPTION_RESERVED};
#[cfg(feature = "server_encrypt")]
use rand::Rng;
#[cfg(feature = "server_encrypt")]
use rsa::pkcs8::der::Decode;
#[cfg(feature = "server_encrypt")]
use rsa::{PublicKey, RsaPublicKey};
#[cfg(feature = "server_encrypt")]
use sha2::Digest;
#[cfg(feature = "server_encrypt")]
use spki::{DecodePublicKey, EncodePublicKey};
#[derive(Clone)] #[derive(Clone)]
pub struct RsaCipher { pub struct RsaCipher {
#[cfg(feature = "server_encrypt")]
inner: Inner, inner: Inner,
} }
#[cfg(feature = "server_encrypt")]
#[derive(Clone)] #[derive(Clone)]
struct Inner { struct Inner {
public_key: RsaPublicKey, public_key: RsaPublicKey,
} }
impl RsaCipher { impl RsaCipher {
#[cfg(feature = "server_encrypt")]
pub fn new(der: &[u8]) -> io::Result<Self> { pub fn new(der: &[u8]) -> io::Result<Self> {
match RsaPublicKey::from_public_key_der(der) { match RsaPublicKey::from_public_key_der(der) {
Ok(public_key) => { Ok(public_key) => {
@@ -30,6 +39,11 @@ impl RsaCipher {
)), )),
} }
} }
#[cfg(not(feature = "server_encrypt"))]
pub fn new(_der: &[u8]) -> io::Result<Self> {
unimplemented!()
}
#[cfg(feature = "server_encrypt")]
pub fn finger(&self) -> io::Result<String> { pub fn finger(&self) -> io::Result<String> {
match self.inner.public_key.to_public_key_der() { match self.inner.public_key.to_public_key_der() {
Ok(der) => match rsa::pkcs8::SubjectPublicKeyInfo::from_der(der.as_bytes()) { Ok(der) => match rsa::pkcs8::SubjectPublicKeyInfo::from_der(der.as_bytes()) {
@@ -51,9 +65,21 @@ impl RsaCipher {
)), )),
} }
} }
#[cfg(not(feature = "server_encrypt"))]
pub fn finger(&self) -> io::Result<String> {
unimplemented!()
}
} }
impl RsaCipher { impl RsaCipher {
#[cfg(not(feature = "server_encrypt"))]
pub fn encrypt<B: AsRef<[u8]> + AsMut<[u8]>>(
&self,
_net_packet: &mut NetPacket<B>,
) -> io::Result<NetPacket<Vec<u8>>> {
unimplemented!()
}
#[cfg(feature = "server_encrypt")]
/// net_packet 必须预留足够长度 /// net_packet 必须预留足够长度
pub fn encrypt<B: AsRef<[u8]> + AsMut<[u8]>>( pub fn encrypt<B: AsRef<[u8]> + AsMut<[u8]>>(
&self, &self,
+4 -4
View File
@@ -116,7 +116,7 @@ impl Sm4CbcCipher {
let mut out = [0u8; 1024 * 4]; let mut out = [0u8; 1024 * 4];
let mut iv = [0u8; 16]; let mut iv = [0u8; 16];
rand::thread_rng().fill_bytes(&mut iv); rand::thread_rng().fill_bytes(&mut iv);
if net_packet.buffer().len() > 1024 * 4 - 32 { if net_packet.data_len() > 1024 * 4 - 32 {
log::error!( log::error!(
"数据异常,长度{}大于1024 * 4 - 32", "数据异常,长度{}大于1024 * 4 - 32",
net_packet.buffer().len() net_packet.buffer().len()
@@ -125,10 +125,9 @@ impl Sm4CbcCipher {
} }
match self.cipher.encrypt(net_packet.buffer(), &iv, &mut out) { match self.cipher.encrypt(net_packet.buffer(), &iv, &mut out) {
Ok(len) => { Ok(len) => {
out[len..len + 16].copy_from_slice(&iv);
net_packet.set_data_len(HEAD_LEN + len + 16)?; net_packet.set_data_len(HEAD_LEN + len + 16)?;
net_packet.set_payload(&out[..len + 16])?; net_packet.payload_mut()[..len].copy_from_slice(&out[..len]);
net_packet.set_encrypt_flag(true); net_packet.payload_mut()[len..].copy_from_slice(&iv);
if let Some(finger) = &self.finger { if let Some(finger) = &self.finger {
let mut nonce_raw = [0; 12]; let mut nonce_raw = [0; 12];
nonce_raw[0..4].copy_from_slice(&net_packet.source().octets()); nonce_raw[0..4].copy_from_slice(&net_packet.source().octets());
@@ -144,6 +143,7 @@ impl Sm4CbcCipher {
net_packet.buffer_mut()[src_data_len..].copy_from_slice(&finger); net_packet.buffer_mut()[src_data_len..].copy_from_slice(&finger);
} }
net_packet.set_encrypt_flag(true);
Ok(()) Ok(())
} }
Err(e) => Err(io::Error::new( Err(e) => Err(io::Error::new(
+2 -1
View File
@@ -155,7 +155,7 @@ impl<B: AsRef<[u8]>> NetPacket<B> {
} }
/// 网关通信的标识 /// 网关通信的标识
pub fn is_gateway(&self) -> bool { pub fn is_gateway(&self) -> bool {
self.buffer.as_ref()[0] & 0x50 == 0x50 self.buffer.as_ref()[0] & 0x40 == 0x40
} }
pub fn version(&self) -> Version { pub fn version(&self) -> Version {
Version::from(self.buffer.as_ref()[0] & 0x0F) Version::from(self.buffer.as_ref()[0] & 0x0F)
@@ -198,6 +198,7 @@ impl<B: AsRef<[u8]> + AsMut<[u8]>> NetPacket<B> {
} }
pub fn set_gateway_flag(&mut self, is_gateway: bool) { pub fn set_gateway_flag(&mut self, is_gateway: bool) {
if is_gateway { if is_gateway {
// 后面的版本再改为0x40,改了之后不兼容1.2.5之前的版本
self.buffer.as_mut()[0] = self.buffer.as_ref()[0] | 0x50 self.buffer.as_mut()[0] = self.buffer.as_ref()[0] | 0x50
} else { } else {
self.buffer.as_mut()[0] = self.buffer.as_ref()[0] & 0xBF self.buffer.as_mut()[0] = self.buffer.as_ref()[0] & 0xBF