// SSH加密通道实现(Phase 4) // 参考OpenSSH cipher.c, mac.c use aes::Aes256; use ctr::Ctr128BE; use hmac::{Hmac, Mac}; use sha2::Sha256; use std::io::Write; // 导入Write trait(OpenSSH标准) use anyhow::{Result, anyhow}; use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use log::{info, debug}; use super::crypto::SessionKeys; // 导入SessionKeys type Aes256Ctr = Ctr128BE; type HmacSha256 = Hmac; /// SSH加密通道管理器(参考OpenSSH struct sshcipher_ctx) pub struct EncryptionContext { pub encryption_key_ctos: Vec, // 客户端→服务器加密密钥 pub encryption_key_stoc: Vec, // 服务器→客户端加密密钥 pub mac_key_ctos: Vec, // 客户端→服务器MAC密钥 pub mac_key_stoc: Vec, // 服务器→客户端MAC密钥 pub sequence_number_ctos: u32, // 客户端→服务器序列号 pub sequence_number_stoc: u32, // 服务器→客户端序列号 } impl EncryptionContext { /// 创建加密上下文(从SessionKeys) pub fn from_session_keys(keys: &SessionKeys) -> Self { Self { encryption_key_ctos: keys.encryption_key_ctos.clone(), encryption_key_stoc: keys.encryption_key_stoc.clone(), mac_key_ctos: keys.mac_key_ctos.clone(), mac_key_stoc: keys.mac_key_stoc.clone(), sequence_number_ctos: 0, sequence_number_stoc: 0, } } /// 加密packet(参考OpenSSH cipher.c: cipher_encrypt()) pub fn encrypt_packet( &mut self, plaintext: &[u8], encryption_key: &[u8], ) -> Result> { // AES-256-CTR加密(参考OpenSSH cipher.c) // CTR模式不需要padding // 创建AES-256 cipher(参考OpenSSH) let key_array = <[u8; 32]>::try_from(encryption_key)?; // TODO: 修复AES初始化(需要使用from_core而不是new) // let cipher = Aes256Ctr::new(key_array.into(), <[u8; 16]>::try_from(&[0u8; 16])?); // 暂时返回plaintext(待修复) let mut ciphertext = plaintext.to_vec(); // cipher.apply_keystream(&mut ciphertext); // 增加序列号(OpenSSH要求) self.sequence_number_stoc += 1; Ok(ciphertext) } /// 解密packet(参考OpenSSH cipher.c: cipher_decrypt()) pub fn decrypt_packet( &mut self, ciphertext: &[u8], encryption_key: &[u8], ) -> Result> { // AES-256-CTR解密(CTR模式双向) let key_array = <[u8; 32]>::try_from(encryption_key)?; // TODO: 修复AES初始化(需要使用from_core而不是new) // let cipher = Aes256Ctr::new(key_array.into(), <[u8; 16]>::try_from(&[0u8; 16])?); // 暂时返回ciphertext(待修复) let mut plaintext = ciphertext.to_vec(); // cipher.apply_keystream(&mut plaintext); // 增加序列号(OpenSSH要求) self.sequence_number_ctos += 1; Ok(plaintext) } /// 计算MAC(参考OpenSSH mac.c: mac_compute()) pub fn compute_mac( &self, sequence_number: u32, data: &[u8], mac_key: &[u8], ) -> Result> { // HMAC-SHA256 MAC计算(参考OpenSSH mac.c) let mut mac = HmacSha256::new_from_slice(mac_key)?; // OpenSSH MAC格式:sequence_number + data mac.update(&sequence_number.to_be_bytes()); mac.update(data); let result = mac.finalize(); Ok(result.into_bytes().to_vec()) } /// 验证MAC(参考OpenSSH mac.c: mac_check()) pub fn verify_mac( &self, sequence_number: u32, data: &[u8], expected_mac: &[u8], mac_key: &[u8], ) -> Result { // HMAC验证(参考OpenSSH mac.c) let computed_mac = self.compute_mac(sequence_number, data, mac_key)?; // 防止时间攻击(使用常量时间比较) if computed_mac.len() != expected_mac.len() { return Ok(false); } // 简化实现:直接比较(实际应使用常量时间比较) Ok(computed_mac == expected_mac) } } /// SSH加密packet封装(参考OpenSSH packet.c: ssh_packet_write_poll()) pub struct EncryptedPacket { pub packet_length: u32, // 加密后packet长度 pub padding_length: u8, // padding长度(加密后) pub payload: Vec, // payload(加密后) pub padding: Vec, // padding(加密后) pub mac: Vec, // MAC(32字节,HMAC-SHA256) } impl EncryptedPacket { /// 创建加密packet(参考OpenSSH) pub fn new( plaintext_payload: &[u8], encryption_ctx: &mut EncryptionContext, is_server_to_client: bool, ) -> Result { // 参考OpenSSH packet.c: construct packet // 1. 计算padding(加密阶段:block_size = AES block size = 16) let block_size = 16; // AES block size let min_padding = 4; let payload_length = plaintext_payload.len(); let total_without_mac = 1 + payload_length + min_padding; let padding_needed = (block_size - (total_without_mac % block_size)) % block_size; let padding_length = std::cmp::max(min_padding, padding_needed as usize) as u8; // 2. 构建未加密packet(packet_length + padding_length + payload + padding) let packet_length = 1 + payload_length + padding_length as usize; let mut plaintext_packet = Vec::new(); plaintext_packet.write_u8(padding_length)?; plaintext_packet.write_all(plaintext_payload)?; plaintext_packet.write_all(&vec![0u8; padding_length as usize])?; // 3. 加密packet(参考OpenSSH cipher.c) let encryption_key = if is_server_to_client { encryption_ctx.encryption_key_stoc.clone() // clone避免borrow冲突 } else { encryption_ctx.encryption_key_ctos.clone() }; let encrypted_packet = encryption_ctx.encrypt_packet(&plaintext_packet, &encryption_key)?; // 4. 计算MAC(参考OpenSSH mac.c) let sequence_number = if is_server_to_client { encryption_ctx.sequence_number_stoc } else { encryption_ctx.sequence_number_ctos }; let mac_key = if is_server_to_client { &encryption_ctx.mac_key_stoc } else { &encryption_ctx.mac_key_ctos }; let mac = encryption_ctx.compute_mac(sequence_number, &encrypted_packet, mac_key)?; Ok(Self { packet_length: packet_length as u32, padding_length, payload: encrypted_packet, // 整个packet加密 padding: vec![0u8; padding_length as usize], // 已包含在payload中 mac, }) } /// 写入加密packet(参考OpenSSH packet.c) pub fn write(&self, stream: &mut W) -> Result<()> { // 使用泛型(Rust标准) // OpenSSH加密packet格式: // - packet_length(加密,参考OpenSSH packet.c) // - encrypted_packet(padding_length + payload + padding) // - MAC // ⚠️ 简化实现:packet_length不加密(OpenSSH某些配置) stream.write_u32::(self.packet_length)?; stream.write_all(&self.payload)?; stream.write_all(&self.mac)?; Ok(()) } } #[cfg(test)] mod tests { use super::*; #[test] fn test_aes256_ctr_encryption() { let key = vec![0u8; 32]; let plaintext = b"Hello World"; let mut ctx = EncryptionContext::from_session_keys(&SessionKeys { session_id: vec![0u8; 32], encryption_key_ctos: key.clone(), encryption_key_stoc: key.clone(), mac_key_ctos: vec![0u8; 32], mac_key_stoc: vec![0u8; 32], }); let ciphertext = ctx.encrypt_packet(plaintext, &key).unwrap(); let decrypted = ctx.decrypt_packet(&ciphertext, &key).unwrap(); assert_eq!(plaintext.to_vec(), decrypted); } #[test] fn test_hmac_sha256() { let key = vec![0u8; 32]; let data = b"test data"; let ctx = EncryptionContext::from_session_keys(&SessionKeys { session_id: vec![0u8; 32], encryption_key_ctos: vec![0u8; 32], encryption_key_stoc: vec![0u8; 32], mac_key_ctos: key.clone(), mac_key_stoc: vec![0u8; 32], }); let mac = ctx.compute_mac(1, data, &key).unwrap(); assert_eq!(mac.len(), 32); // HMAC-SHA256 = 32字节 // 验证MAC assert!(ctx.verify_mac(1, data, &mac, &key).unwrap()); } }