File size: 7,105 Bytes
3c2af29 |
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 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 |
use base64::{engine::general_purpose::STANDARD as BASE64, Engine as _};
use rand::Rng;
use sha2::{Digest, Sha256};
pub fn generate_hash() -> String {
let random_bytes = rand::thread_rng().gen::<[u8; 32]>();
let mut hasher = Sha256::new();
hasher.update(random_bytes);
hex::encode(hasher.finalize())
}
fn obfuscate_bytes(bytes: &mut [u8]) {
let mut prev: u8 = 165;
for (idx, byte) in bytes.iter_mut().enumerate() {
let old_value = *byte;
*byte = (old_value ^ prev).wrapping_add((idx % 256) as u8);
prev = *byte;
}
}
fn deobfuscate_bytes(bytes: &mut [u8]) {
let mut prev: u8 = 165;
for (idx, byte) in bytes.iter_mut().enumerate() {
let temp = *byte;
*byte = (*byte).wrapping_sub((idx % 256) as u8) ^ prev;
prev = temp;
}
}
pub fn generate_timestamp_header() -> String {
let timestamp = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs()
/ 1_000;
let mut timestamp_bytes = vec![
((timestamp >> 8) & 0xFF) as u8,
(0xFF & timestamp) as u8,
((timestamp >> 24) & 0xFF) as u8,
((timestamp >> 16) & 0xFF) as u8,
((timestamp >> 8) & 0xFF) as u8,
(0xFF & timestamp) as u8,
];
obfuscate_bytes(&mut timestamp_bytes);
BASE64.encode(×tamp_bytes)
}
pub fn generate_checksum(device_id: &str, mac_addr: Option<&str>) -> String {
let encoded = generate_timestamp_header();
match mac_addr {
Some(mac) => format!("{}{}/{}", encoded, device_id, mac),
None => format!("{}{}", encoded, device_id),
}
}
pub fn generate_checksum_with_default() -> String {
generate_checksum(&generate_hash(), Some(&generate_hash()))
}
pub fn generate_checksum_with_repair(checksum: &str) -> String {
let bytes = checksum.as_bytes();
let len = bytes.len();
// 长度快速检查
if len != 72 && len != 129 && len != 137 {
return generate_checksum_with_default();
}
// 单次遍历完成所有字符校验
for (i, &b) in bytes.iter().enumerate() {
let valid = match (len, i) {
// 通用字符校验(排除非法字符)
(_, _) if !b.is_ascii_alphanumeric() && b != b'/' && b != b'+' && b != b'=' => false,
// 72字节格式:时间戳(8) + 设备哈希(64)
(72, 8..=71) => b.is_ascii_hexdigit(),
// 129字节格式:设备哈希(64) + '/' + MAC哈希(64)
(129, 0..=63) => b.is_ascii_hexdigit(),
(129, 64) => b == b'/',
(129, 65..=128) => b.is_ascii_hexdigit(),
// 137字节格式:时间戳(8) + 设备哈希(64) + '/' + MAC哈希(64)
(137, 8..=71) => b.is_ascii_hexdigit(),
(137, 72) => b == b'/',
(137, 73..=136) => b.is_ascii_hexdigit(),
// 时间戳部分不需要校验
(72 | 137, 0..=7) => true,
_ => unreachable!(),
};
if !valid {
return generate_checksum_with_default();
}
}
// 校验通过后构造结果
match len {
72 => format!(
"{}{}/{}",
generate_timestamp_header(),
unsafe { std::str::from_utf8_unchecked(&bytes[8..]) },
generate_hash()
),
129 => format!(
"{}{}/{}",
generate_timestamp_header(),
unsafe { std::str::from_utf8_unchecked(&bytes[..64]) },
unsafe { std::str::from_utf8_unchecked(&bytes[65..]) }
),
137 => format!(
"{}{}/{}",
generate_timestamp_header(),
unsafe { std::str::from_utf8_unchecked(&bytes[8..72]) },
unsafe { std::str::from_utf8_unchecked(&bytes[73..]) }
),
_ => unreachable!(),
}
}
pub fn extract_time_ks(timestamp_base64: &str) -> Option<u64> {
let mut timestamp_bytes = BASE64.decode(timestamp_base64).ok()?;
if timestamp_bytes.len() != 6 {
return None;
}
deobfuscate_bytes(&mut timestamp_bytes);
if timestamp_bytes[0] != timestamp_bytes[4] || timestamp_bytes[1] != timestamp_bytes[5] {
return None;
}
// 使用后四位还原 timestamp
Some(
((timestamp_bytes[2] as u64) << 24)
| ((timestamp_bytes[3] as u64) << 16)
| ((timestamp_bytes[4] as u64) << 8)
| (timestamp_bytes[5] as u64),
)
}
pub fn validate_checksum(checksum: &str) -> bool {
let bytes = checksum.as_bytes();
let len = bytes.len();
// 长度门控
if len != 72 && len != 137 {
return false;
}
// 单次遍历完成所有字符校验
for (i, &b) in bytes.iter().enumerate() {
let valid = match (len, i) {
// 通用字符校验(排除非法字符)
(_, _) if !b.is_ascii_alphanumeric() && b != b'/' && b != b'+' && b != b'=' => false,
// 格式校验
(72, 0..=7) => true, // 时间戳部分(由extract_time_ks验证)
(72, 8..=71) => b.is_ascii_hexdigit(),
(137, 0..=7) => true, // 时间戳
(137, 8..=71) => b.is_ascii_hexdigit(), // 设备哈希
(137, 72) => b == b'/', // 分割符(索引72是第73个字符)
(137, 73..=136) => b.is_ascii_hexdigit(), // MAC哈希
_ => unreachable!(),
};
if !valid {
return false;
}
}
// 统一时间戳验证(无需分层)
let time_valid = extract_time_ks(&checksum[..8]).is_some();
// 附加MAC哈希长度校验(仅137字符需要)
let mac_hash_valid = if len == 137 {
checksum[73..].len() == 64 // 确保MAC哈希长度为64
} else {
true // 72字符无需此检查
};
time_valid && mac_hash_valid
}
/// 从校验通过的checksum中提取哈希值(需先通过validate_checksum验证)
/// 返回 (device_hash, mac_hash) ,mac_hash可能为空Vec
pub fn extract_hashes(checksum: &str) -> Option<(Vec<u8>, Vec<u8>)> {
// 前置条件:必须通过校验(确保长度和格式正确)
if !validate_checksum(checksum) {
return None;
}
// 根据长度直接切割,无需字符级验证(validate_checksum已保证)
match checksum.len() {
72 => {
// 格式:8字节时间戳 + 64字节设备哈希
let device_hash = hex::decode(&checksum[8..]).ok()?; // 8..72
Some((device_hash, Vec::new()))
}
137 => {
// 格式:8时间戳 + 64设备哈希 + '/' + 64MAC哈希
// 直接按固定位置切割(validate_checksum已确保索引72是'/')
let device_hash = hex::decode(&checksum[8..72]).ok()?;
let mac_hash = hex::decode(&checksum[73..]).ok()?; // 73..137
Some((device_hash, mac_hash))
}
// validate_checksum已过滤其他长度,此处应为不可达代码
_ => unreachable!("Invalid length after validation: {}", checksum.len()),
}
}
|