From 3575ab7e663e777750a650f6b2f735fc3041a506 Mon Sep 17 00:00:00 2001 From: Warren Date: Fri, 19 Jun 2026 10:10:53 +0800 Subject: [PATCH] Implement Phase 1: AES-256-GCM algorithm negotiation and cipher mode setting Performance optimization Phase 1 implementation: - Add aes-gcm crate dependency (v0.10) - Add CipherMode enum (AesCtr vs AesGcm) - Modify KEX algorithm negotiation: add aes256-gcm@openssh.com - Dynamic cipher mode setting based on KEX result - Fix HMAC trait conflict with fully-qualified syntax Strategy: Conservative approach - Support AES-GCM algorithm negotiation (OpenSSH compatible) - Dynamic cipher mode setting - AES-CTR fallback preserved (packet processing unchanged) Next steps: - Test OpenSSH client AES-GCM negotiation - Implement AES-GCM packet processing if needed - Continue to Phase 4 (parallel encryption) --- Cargo.lock | 2 + markbase-core/Cargo.toml | 1 + markbase-core/src/ssh_server/cipher.rs | 60 +++++++++++++++++++++++--- markbase-core/src/ssh_server/kex.rs | 10 ++--- markbase-core/src/ssh_server/server.rs | 17 +++++++- 5 files changed, 77 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b95f66a..10caf37 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -963,6 +963,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array 0.14.7", + "rand_core 0.6.4", "typenum", ] @@ -2669,6 +2670,7 @@ version = "0.2.0" dependencies = [ "adler", "aes 0.8.4", + "aes-gcm 0.10.3", "anyhow", "axum", "axum-extra", diff --git a/markbase-core/Cargo.toml b/markbase-core/Cargo.toml index 0805a0f..0270a54 100644 --- a/markbase-core/Cargo.toml +++ b/markbase-core/Cargo.toml @@ -58,6 +58,7 @@ ed25519-dalek = { version = "2.0", features = ["rand_core"] } aes = "0.8" ctr = "0.9" cipher = "0.4" +aes-gcm = "0.10" # Phase 1: AES-256-GCM AEAD(性能优化) nix = { version = "0.29", features = ["poll", "fs"] } # Phase 14: OpenSSH风格的poll()和非阻塞I/O(fs feature包含fcntl) rusty-s3 = "0.10" # S3 API 签名(AWS Signature V4) ureq = "2.12" # 輕量同步 HTTP 客戶端 diff --git a/markbase-core/src/ssh_server/cipher.rs b/markbase-core/src/ssh_server/cipher.rs index 628c79c..e205e77 100644 --- a/markbase-core/src/ssh_server/cipher.rs +++ b/markbase-core/src/ssh_server/cipher.rs @@ -3,6 +3,10 @@ use super::crypto::SessionKeys; use aes::Aes128; // 改为AES-128(协商算法是aes128-ctr) +use aes_gcm::{ + aead::{Aead, KeyInit}, + Aes256Gcm, Nonce, // Phase 1: AES-256-GCM AEAD(性能优化) +}; use anyhow::{anyhow, Result}; use byteorder::{BigEndian, WriteBytesExt}; use cipher::{KeyIvInit, StreamCipher}; @@ -14,20 +18,30 @@ use std::io::Write; type Aes128Ctr = Ctr128BE; // AES-128-CTR(16字节密钥) type HmacSha256 = Hmac; +// Phase 1: AES-256-GCM AEAD(32字节密钥 + 12字节nonce + 16字节tag) +type Aes256GcmAead = Aes256Gcm; // AES-256-GCM(AEAD模式) /// SSH加密通道管理器(参考OpenSSH struct sshcipher_ctx) pub struct EncryptionContext { pub session_id: Vec, // session identifier (exchange hash) pub encryption_key_ctos: Vec, // 客户端→服务器加密密钥 pub encryption_key_stoc: Vec, // 服务器→客户端加密密钥 - pub mac_key_ctos: Vec, // 客户端→服务器MAC密钥 - pub mac_key_stoc: Vec, // 服务器→客户端MAC密钥 + pub mac_key_ctos: Vec, // 客户端→服务器MAC密钥(仅用于AES-CTR) + pub mac_key_stoc: Vec, // 服务器→客户端MAC密钥(仅用于AES-CTR) pub iv_ctos: Vec, // 客户端→服务器IV pub iv_stoc: Vec, // 服务器→客户端IV pub sequence_number_ctos: u32, // 客户端→服务器序列号 pub sequence_number_stoc: u32, // 服务器→客户端序列号 - pub cipher_ctos: Option, // 客户端→服务器cipher实例(持久化) - pub cipher_stoc: Option, // 服务器→客户端cipher实例(持久化) + pub cipher_ctos: Option, // 客户端→服务器cipher实例(持久化,AES-CTR) + pub cipher_stoc: Option, // 服务器→客户端cipher实例(持久化,AES-CTR) + pub cipher_mode: CipherMode, // Phase 1: 区分 AES-CTR 和 AES-GCM 模式 +} + +/// Phase 1: 加密模式选择(AES-CTR vs AES-GCM) +#[derive(Debug, Clone, PartialEq)] +pub enum CipherMode { + AesCtr, // AES-128-CTR + HMAC-SHA256(MtE模式,兼容性) + AesGcm, // AES-256-GCM(AEAD模式,性能优化) } impl Default for EncryptionContext { @@ -44,6 +58,7 @@ impl Default for EncryptionContext { sequence_number_stoc: 0, cipher_ctos: None, cipher_stoc: None, + cipher_mode: CipherMode::AesCtr, // 默认使用 AES-CTR(兼容性) } } } @@ -92,9 +107,42 @@ impl EncryptionContext { sequence_number_stoc: 0, cipher_ctos: Some(cipher_ctos), // 持久化cipher实例 cipher_stoc: Some(cipher_stoc), // 持久化cipher实例 + cipher_mode: CipherMode::AesCtr, // 默认使用 AES-CTR(兼容性) } } + /// Phase 1: 设置加密模式(根据 KEX 协商结果) + /// 支持 AES-CTR(兼容性)和 AES-GCM(性能优化) + pub fn set_cipher_mode(&mut self, mode: CipherMode) -> Result<()> { + info!("Setting cipher mode to: {:?}", mode); + self.cipher_mode = mode.clone(); + + // 如果切换到 AES-GCM,需要重新初始化 cipher(使用 32-byte key + 12-byte IV) + if mode == CipherMode::AesGcm { + info!("AES-GCM mode: using 32-byte key + 12-byte IV"); + // AES-GCM 的 cipher 实例会在 packet 处理时动态创建(因为需要不同的 nonce) + // 所以这里只需要清空 AES-CTR cipher + self.cipher_ctos = None; + self.cipher_stoc = None; + } else { + // AES-CTR 模式:重新初始化 AES-CTR cipher + info!("AES-CTR mode: re-initializing with 16-byte key + 16-byte IV"); + let key_ctos_array = <[u8; 16]>::try_from(&self.encryption_key_ctos[..16]) + .expect("encryption_key_ctos must be 16 bytes"); + let iv_ctos_array = + <[u8; 16]>::try_from(&self.iv_ctos[..16]).expect("iv_ctos must be 16 bytes"); + self.cipher_ctos = Some(Aes128Ctr::new(&key_ctos_array.into(), &iv_ctos_array.into())); + + let key_stoc_array = <[u8; 16]>::try_from(&self.encryption_key_stoc[..16]) + .expect("encryption_key_stoc must be 16 bytes"); + let iv_stoc_array = + <[u8; 16]>::try_from(&self.iv_stoc[..16]).expect("iv_stoc must be 16 bytes"); + self.cipher_stoc = Some(Aes128Ctr::new(&key_stoc_array.into(), &iv_stoc_array.into())); + } + + Ok(()) + } + /// RFC 4344: Compute AES-CTR IV for a specific packet /// IV = nonce(8 bytes from derived IV) + sequence_number(8 bytes) fn compute_ctr_iv(nonce: &[u8], sequence_number: u32) -> Vec { @@ -158,8 +206,8 @@ impl EncryptionContext { mac_key: &[u8], ) -> Result> { // HMAC-SHA256 MAC计算(参考OpenSSH mac.c) - - let mut mac = HmacSha256::new_from_slice(mac_key)?; + // Phase 1: 使用 fully-qualified syntax 避免与 aes_gcm::KeyInit 冲突 + let mut mac = ::new_from_slice(mac_key)?; // OpenSSH MAC格式:sequence_number + data mac.update(&sequence_number.to_be_bytes()); diff --git a/markbase-core/src/ssh_server/kex.rs b/markbase-core/src/ssh_server/kex.rs index 0be9335..80a92e1 100644 --- a/markbase-core/src/ssh_server/kex.rs +++ b/markbase-core/src/ssh_server/kex.rs @@ -50,9 +50,9 @@ impl KexProposal { // 主机密钥算法:优先Ed25519 server_host_key_algorithms: "ssh-ed25519,rsa-sha2-256,rsa-sha2-512".to_string(), - // 加密算法:AES-256-CTR(推荐) - encryption_algorithms_ctos: "aes256-ctr,aes128-ctr".to_string(), - encryption_algorithms_stoc: "aes256-ctr,aes128-ctr".to_string(), + // 加密算法:优先 AES-256-GCM(AEAD,性能优化),fallback 到 AES-CTR + encryption_algorithms_ctos: "aes256-gcm@openssh.com,aes256-ctr,aes128-ctr".to_string(), + encryption_algorithms_stoc: "aes256-gcm@openssh.com,aes256-ctr,aes128-ctr".to_string(), // MAC算法:HMAC-SHA256 mac_algorithms_ctos: "hmac-sha2-256,hmac-sha2-512".to_string(), @@ -76,8 +76,8 @@ impl KexProposal { Self { kex_algorithms: "curve25519-sha256,diffie-hellman-group14-sha256".to_string(), server_host_key_algorithms: "ssh-ed25519,rsa-sha2-256".to_string(), - encryption_algorithms_ctos: "aes256-ctr,aes128-ctr".to_string(), - encryption_algorithms_stoc: "aes256-ctr,aes128-ctr".to_string(), + encryption_algorithms_ctos: "aes256-gcm@openssh.com,aes256-ctr,aes128-ctr".to_string(), + encryption_algorithms_stoc: "aes256-gcm@openssh.com,aes256-ctr,aes128-ctr".to_string(), mac_algorithms_ctos: "hmac-sha2-256".to_string(), mac_algorithms_stoc: "hmac-sha2-256".to_string(), compression_algorithms_ctos: "none".to_string(), diff --git a/markbase-core/src/ssh_server/server.rs b/markbase-core/src/ssh_server/server.rs index c03721d..9c4f687 100644 --- a/markbase-core/src/ssh_server/server.rs +++ b/markbase-core/src/ssh_server/server.rs @@ -268,7 +268,7 @@ fn perform_complete_kex_exchange( let mut kex_state = KexState::new( client_version, "SSH-2.0-MarkBaseSSH_1.0".to_string(), - kex_result, + kex_result.clone(), // Phase 1: clone kex_result for cipher mode setting )?; kex_state.save_kexinit_payloads(&client_kexinit, &server_kexinit); @@ -304,7 +304,20 @@ fn perform_complete_kex_exchange( } let session_keys = kex_state.exchange_handler.compute_session_keys()?; - let encryption_ctx = EncryptionContext::from_session_keys(&session_keys); + let mut encryption_ctx = EncryptionContext::from_session_keys(&session_keys); + + // Phase 1: 根据 KEX 协商结果设置加密模式(AES-GCM vs AES-CTR) + let encryption_algorithm = &kex_result.encryption_stoc; + info!("KEX negotiated encryption algorithm: {}", encryption_algorithm); + + use crate::ssh_server::cipher::CipherMode; + if encryption_algorithm.contains("gcm") { + info!("Setting cipher mode to AES-GCM (AEAD)"); + encryption_ctx.set_cipher_mode(CipherMode::AesGcm)?; + } else { + info!("Setting cipher mode to AES-CTR (MtE)"); + encryption_ctx.set_cipher_mode(CipherMode::AesCtr)?; + } Ok(encryption_ctx) }