diff --git a/Cargo.lock b/Cargo.lock index 37827b4..5c6c307 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2653,6 +2653,7 @@ dependencies = [ "bcrypt", "byteorder", "chrono", + "cipher 0.4.4", "clap", "ctr 0.9.2", "dashmap", diff --git a/markbase-core/Cargo.toml b/markbase-core/Cargo.toml index 19b4e8b..a855e42 100644 --- a/markbase-core/Cargo.toml +++ b/markbase-core/Cargo.toml @@ -55,6 +55,7 @@ x25519-dalek = "2.0" ed25519-dalek = { version = "2.0", features = ["rand_core"] } aes = "0.8" ctr = "0.9" +cipher = "0.4" [features] default = [] # 默认不启用可选格式 diff --git a/markbase-core/src/ssh_server/cipher.rs b/markbase-core/src/ssh_server/cipher.rs index afa9944..ecbec1a 100644 --- a/markbase-core/src/ssh_server/cipher.rs +++ b/markbase-core/src/ssh_server/cipher.rs @@ -5,11 +5,12 @@ use aes::Aes256; use ctr::Ctr128BE; use hmac::{Hmac, Mac}; use sha2::Sha256; -use std::io::Write; // 导入Write trait(OpenSSH标准) +use cipher::{KeyIvInit, StreamCipher}; +use std::io::Write; use anyhow::{Result, anyhow}; use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use log::{info, debug}; -use super::crypto::SessionKeys; // 导入SessionKeys +use super::crypto::SessionKeys; type Aes256Ctr = Ctr128BE; type HmacSha256 = Hmac; @@ -42,20 +43,16 @@ impl EncryptionContext { &mut self, plaintext: &[u8], encryption_key: &[u8], + iv: &[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])?); + let iv_array = <[u8; 16]>::try_from(iv)?; + + let mut cipher = Aes256Ctr::new(&key_array.into(), &iv_array.into()); - // 暂时返回plaintext(待修复) let mut ciphertext = plaintext.to_vec(); - // cipher.apply_keystream(&mut ciphertext); + cipher.apply_keystream(&mut ciphertext); - // 增加序列号(OpenSSH要求) self.sequence_number_stoc += 1; Ok(ciphertext) @@ -66,18 +63,16 @@ impl EncryptionContext { &mut self, ciphertext: &[u8], encryption_key: &[u8], + iv: &[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])?); + let iv_array = <[u8; 16]>::try_from(iv)?; + + let mut cipher = Aes256Ctr::new(&key_array.into(), &iv_array.into()); - // 暂时返回ciphertext(待修复) let mut plaintext = ciphertext.to_vec(); - // cipher.apply_keystream(&mut plaintext); + cipher.apply_keystream(&mut plaintext); - // 增加序列号(OpenSSH要求) self.sequence_number_ctos += 1; Ok(plaintext) @@ -139,11 +134,9 @@ impl EncryptedPacket { plaintext_payload: &[u8], encryption_ctx: &mut EncryptionContext, is_server_to_client: bool, + iv: &[u8], ) -> Result { - // 参考OpenSSH packet.c: construct packet - - // 1. 计算padding(加密阶段:block_size = AES block size = 16) - let block_size = 16; // AES block size + let block_size = 16; let min_padding = 4; let payload_length = plaintext_payload.len(); @@ -151,24 +144,25 @@ impl EncryptedPacket { 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 mut random_padding = vec![0u8; padding_length as usize]; + use rand::RngCore; + rand::thread_rng().fill_bytes(&mut random_padding); + plaintext_packet.write_all(&random_padding)?; + let encryption_key = if is_server_to_client { - encryption_ctx.encryption_key_stoc.clone() // clone避免borrow冲突 + encryption_ctx.encryption_key_stoc.clone() } else { encryption_ctx.encryption_key_ctos.clone() }; - let encrypted_packet = encryption_ctx.encrypt_packet(&plaintext_packet, &encryption_key)?; + let encrypted_packet = encryption_ctx.encrypt_packet(&plaintext_packet, &encryption_key, iv)?; - // 4. 计算MAC(参考OpenSSH mac.c) let sequence_number = if is_server_to_client { encryption_ctx.sequence_number_stoc } else { @@ -181,13 +175,17 @@ impl EncryptedPacket { &encryption_ctx.mac_key_ctos }; - let mac = encryption_ctx.compute_mac(sequence_number, &encrypted_packet, mac_key)?; + let mut mac_data = Vec::new(); + mac_data.write_u32::(packet_length as u32)?; + mac_data.extend_from_slice(&encrypted_packet); + + let mac = encryption_ctx.compute_mac(sequence_number, &mac_data, mac_key)?; Ok(Self { packet_length: packet_length as u32, padding_length, - payload: encrypted_packet, // 整个packet加密 - padding: vec![0u8; padding_length as usize], // 已包含在payload中 + payload: encrypted_packet, + padding: random_padding, mac, }) }