1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
use std::str;
use crypto::hash::{HasherBuilder, HasherType};
use common::utils::current_timestamp;
use common::dialer::Dialer;
use common::hex::ToHex;
use common::bytes::BytesAbleNum;
#[derive(Debug)]
pub enum Configuration {
Zhejiang,
SingleNet,
Enterprise,
Chongqing,
Chongqing2,
Wuhan,
Qinghai,
Xinjiang,
Hebei,
Shandong,
Shanxi,
Gansu,
}
#[derive(Debug)]
pub struct NetkeeperDialer {
pub share_key: String,
pub prefix: String,
}
impl NetkeeperDialer {
pub fn new(share_key: &str, prefix: &str) -> Self {
NetkeeperDialer {
share_key: share_key.to_string(),
prefix: prefix.to_string(),
}
}
pub fn encrypt_account(&self, username: &str, timestamp: Option<u32>) -> String {
let username = username.to_uppercase();
let timenow = timestamp.unwrap_or_else(current_timestamp);
let time_div_by_five: u32 = timenow / 5;
let mut pin27_byte: [u8; 6] = [0; 6];
let pin27_str;
{
let mut time_hash: [u8; 4] = [0; 4];
for (i, code) in time_hash.iter_mut().enumerate() {
for j in 0..8 {
*code += ((((time_div_by_five >> (i + 4 * j)) & 1) << (7 - j)) & 0xFF) as u8;
}
}
pin27_byte[0] = (time_hash[0] >> 2) & 0x3F;
pin27_byte[1] = ((time_hash[0] & 0x03) << 4) | ((time_hash[1] >> 4) & 0x0F);
pin27_byte[2] = ((time_hash[1] & 0x0F) << 2) | ((time_hash[2] >> 6) & 0x03);
pin27_byte[3] = time_hash[2] & 0x3F;
pin27_byte[4] = (time_hash[3] >> 2) & 0x3F;
pin27_byte[5] = (time_hash[3] & 0x03) << 4;
for byte in pin27_byte.iter_mut().take(6) {
*byte += 0x20;
if *byte > 0x40 {
*byte += 1;
}
}
unsafe {
pin27_str = str::from_utf8_unchecked(&pin27_byte);
}
}
let pin89_str;
{
let mut md5 = HasherBuilder::build(HasherType::MD5);
md5.update(&time_div_by_five.as_bytes_be());
md5.update(username.split('@').nth(0).unwrap().as_bytes());
md5.update(self.share_key.as_bytes());
let hashed_bytes = md5.finish();
pin89_str = hashed_bytes[0..1].to_hex();
}
format!("{}{}{}{}", self.prefix, pin27_str, pin89_str, username)
}
}
impl Configuration {
pub fn share_key(&self) -> &'static str {
match *self {
Configuration::Zhejiang => "zjxinlisx01",
Configuration::SingleNet => "singlenet01",
Configuration::Enterprise => "zjxinlisx02",
Configuration::Chongqing => "cqxinliradius002",
Configuration::Chongqing2 => "xianxinli1radius",
Configuration::Wuhan => "hubtxinli01",
Configuration::Qinghai => "shd@xiaoyuan0002",
Configuration::Xinjiang => "xinjiang@0724",
Configuration::Hebei => "hebeicncxinli002",
Configuration::Shandong => "shandongmobile13",
Configuration::Shanxi => "sh_xi@xiaoyuan01",
Configuration::Gansu => "xiaoyuanyixun001",
}
}
pub fn prefix(&self) -> &'static str {
match *self {
_ => "\r\n",
}
}
}
impl Dialer for NetkeeperDialer {
type C = Configuration;
fn load_from_config(config: Self::C) -> Self {
NetkeeperDialer::new(config.share_key(), config.prefix())
}
}