diff --git a/markbase-core/src/ssh_server/cipher.rs b/markbase-core/src/ssh_server/cipher.rs index 96b0f50..d38ebb3 100644 --- a/markbase-core/src/ssh_server/cipher.rs +++ b/markbase-core/src/ssh_server/cipher.rs @@ -278,6 +278,7 @@ pub struct EncryptedPacket { impl EncryptedPacket { /// 创建加密packet(参考OpenSSH cipher.c) /// Phase 1: 支持 AES-CTR (MtE) 和 AES-GCM (AEAD) 两种模式 + /// Phase 3: 支持压缩(压缩发生在加密之前) pub fn new( plaintext_payload: &[u8], encryption_ctx: &mut EncryptionContext, @@ -285,8 +286,23 @@ impl EncryptedPacket { ) -> Result { let block_size = 16; let min_padding = 4; - - let payload_length = plaintext_payload.len(); + + // Phase 3: 压缩 payload(如果启用) + // 压缩顺序:压缩 → 加密(参考 RFC 4253 §6.2) + let compressed_payload = if is_server_to_client { + // Server → Client: 使用 compression_stoc + if encryption_ctx.compression_stoc.is_enabled() { + info!("Compressing payload (server→client, {} bytes)", plaintext_payload.len()); + encryption_ctx.compression_stoc.compress(plaintext_payload)? + } else { + plaintext_payload.to_vec() + } + } else { + // Client → Server: 使用 compression_ctos(server 解压缩,这里不压缩) + plaintext_payload.to_vec() + }; + + let payload_length = compressed_payload.len(); // Padding calculation: // AES-GCM: RFC 4253 body (padding_length + payload + padding = packet_length) must be % 16 == 0 @@ -321,7 +337,7 @@ impl EncryptedPacket { let total_plaintext_size = 1 + payload_length + padding_length as usize; let mut plaintext_payload_buffer = SshBuf::with_capacity(total_plaintext_size); plaintext_payload_buffer.put(&[padding_length])?; - plaintext_payload_buffer.put(plaintext_payload)?; + plaintext_payload_buffer.put(&compressed_payload)?; let mut random_padding = vec![0u8; padding_length as usize]; use rand::RngCore; @@ -421,7 +437,7 @@ impl EncryptedPacket { let total_plaintext_size = 1 + payload_length + padding_length as usize; let mut plaintext_payload_buffer = SshBuf::with_capacity(total_plaintext_size); plaintext_payload_buffer.put(&[padding_length])?; - plaintext_payload_buffer.put(plaintext_payload)?; + plaintext_payload_buffer.put(&compressed_payload)?; let mut random_padding = vec![0u8; padding_length as usize]; use rand::RngCore; @@ -505,7 +521,7 @@ impl EncryptedPacket { let mut plaintext_packet = SshBuf::with_capacity(total_packet_size); plaintext_packet.put(&(packet_length as u32).to_be_bytes())?; plaintext_packet.put(&[padding_length])?; - plaintext_packet.put(plaintext_payload)?; + plaintext_packet.put(&compressed_payload)?; let mut random_padding = vec![0u8; padding_length as usize]; use rand::RngCore; @@ -705,7 +721,23 @@ impl EncryptedPacket { info!("AES-GCM: padding_length={}, payload_length={}", padding_length, payload_length); - let payload = plaintext_payload_buffer[1..1 + payload_length].to_vec(); + let compressed_payload = plaintext_payload_buffer[1..1 + payload_length].to_vec(); + + // Phase 3: 解压缩 payload(如果启用) + // 解压缩顺序:解密 → 解压缩(参考 RFC 4253 §6.2) + let payload = if is_client_to_server { + // Client → Server: 使用 compression_ctos + if encryption_ctx.compression_ctos.is_enabled() { + info!("Decompressing payload (client→server, {} bytes)", compressed_payload.len()); + encryption_ctx.compression_ctos.decompress(&compressed_payload)? + } else { + compressed_payload + } + } else { + // Server → Client: 使用 compression_stoc(client 解压缩,这里不解压缩) + compressed_payload + }; + let padding = Vec::new(); // AES-GCM: padding 不需要存储(write 时使用 payload 中的 ciphertext) // 9. 提取 GCM tag (last 16 bytes of ciphertext) @@ -917,6 +949,23 @@ impl EncryptedPacket { let mut payload = Vec::with_capacity(payload_length); payload.extend_from_slice(payload_part1); payload.extend_from_slice(payload_part2); + + // Phase 3: 解压缩 payload(如果启用) + // 解压缩顺序:解密 → 解压缩(参考 RFC 4253 §6.2) + let decompressed_payload = if is_client_to_server { + // Client → Server: 使用 compression_ctos + if encryption_ctx.compression_ctos.is_enabled() { + info!("Decompressing payload (client→server, {} bytes)", payload.len()); + encryption_ctx.compression_ctos.decompress(&payload)? + } else { + payload + } + } else { + // Server → Client: 使用 compression_stoc(client 解压缩,这里不解压缩) + payload + }; + + let payload = decompressed_payload; // 提取padding(从remaining_encrypted的末尾) let padding = remaining_encrypted[payload_part2_len..].to_vec();