use std::net::TcpStream;
use std::io::Read;
pub struct Sha1 {
state: [u32; 5],
buffer: Vec<u8>,
count: u64,
}
impl Sha1 {
pub fn new() -> Self {
Self {
state: [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0],
buffer: Vec::new(),
count: 0,
}
}
pub fn update(&mut self, data: &[u8]) {
self.buffer.extend_from_slice(data);
self.count += (data.len() * 8) as u64;
}
pub fn finalize(mut self) -> [u8; 20] {
self.buffer.push(0x80);
while (self.buffer.len() % 64) != 56 { self.buffer.push(0); }
self.buffer.extend_from_slice(&self.count.to_be_bytes());
for chunk in self.buffer.chunks_exact(64) {
let mut w = [0u32; 80];
for i in 0..16 {
w[i] = u32::from_be_bytes([chunk[i*4], chunk[i*4+1], chunk[i*4+2], chunk[i*4+3]]);
}
for i in 16..80 {
w[i] = (w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]).rotate_left(1);
}
let [mut a, mut b, mut c, mut d, mut e] = self.state;
for i in 0..80 {
let (f, k) = match i {
0..=19 => ((b & c) | (!b & d), 0x5A827999),
20..=39 => (b ^ c ^ d, 0x6ED9EBA1),
40..=59 => ((b & c) | (b & d) | (c & d), 0x8F1BBCDC),
_ => (b ^ c ^ d, 0xCA62C1D6),
};
let temp = a.rotate_left(5).wrapping_add(f).wrapping_add(e).wrapping_add(k).wrapping_add(w[i]);
e = d; d = c; c = b.rotate_left(30); b = a; a = temp;
}
self.state[0] = self.state[0].wrapping_add(a);
self.state[1] = self.state[1].wrapping_add(b);
self.state[2] = self.state[2].wrapping_add(c);
self.state[3] = self.state[3].wrapping_add(d);
self.state[4] = self.state[4].wrapping_add(e);
}
let mut out = [0u8; 20];
for i in 0..5 { out[i*4..(i+1)*4].copy_from_slice(&self.state[i].to_be_bytes()); }
out
}
}
pub fn base64_encode(input: &[u8]) -> String {
const CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
let mut result = String::with_capacity((input.len() + 2) / 3 * 4);
for chunk in input.chunks(3) {
let b = match chunk.len() {
3 => (chunk[0] as u32) << 16 | (chunk[1] as u32) << 8 | (chunk[2] as u32),
2 => (chunk[0] as u32) << 16 | (chunk[1] as u32) << 8,
_ => (chunk[0] as u32) << 16,
};
result.push(CHARSET[(b >> 18 & 0x3F) as usize] as char);
result.push(CHARSET[(b >> 12 & 0x3F) as usize] as char);
if chunk.len() > 1 { result.push(CHARSET[(b >> 6 & 0x3F) as usize] as char); } else { result.push('='); }
if chunk.len() > 2 { result.push(CHARSET[(b & 0x3F) as usize] as char); } else { result.push('='); }
}
result
}
pub struct WSFrame {
pub payload: Vec<u8>,
}
impl WSFrame {
pub fn read(stream: &mut TcpStream) -> std::io::Result<Self> {
let mut head = [0u8; 2];
stream.read_exact(&mut head)?;
let is_masked = (head[1] & 0x80) != 0;
let mut len = (head[1] & 0x7F) as usize;
if len == 126 {
let mut extended_len = [0u8; 2];
stream.read_exact(&mut extended_len)?;
len = u16::from_be_bytes(extended_len) as usize;
} else if len == 127 {
let mut extended_len = [0u8; 8];
stream.read_exact(&mut extended_len)?;
len = u64::from_be_bytes(extended_len) as usize;
}
let mut payload = vec![0u8; len];
if is_masked {
let mut mask = [0u8; 4];
stream.read_exact(&mut mask)?;
stream.read_exact(&mut payload)?;
for i in 0..len {
payload[i] ^= mask[i % 4];
}
} else {
stream.read_exact(&mut payload)?;
}
Ok(WSFrame { payload })
}
}