From 382ea2e28bdac2cdd9ce50c594e7f39cddb9afdb Mon Sep 17 00:00:00 2001 From: Warren Date: Mon, 22 Jun 2026 03:18:22 +0800 Subject: [PATCH] Phase 1.3: SMB3 packet encryption handling complete - Add handle_encrypted_frame() to dispatch.rs - Detect TRANSFORM_HEADER magic (0x534D4220) - Decrypt incoming packets using session.encryption_key - Encrypt outgoing responses - All encryption tests pass (3 passed) Phase 1 SMB3 encryption complete: ~380 lines total --- vendor/smb-server/src/dispatch.rs | 99 +++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/vendor/smb-server/src/dispatch.rs b/vendor/smb-server/src/dispatch.rs index 5ff1995..b72b602 100644 --- a/vendor/smb-server/src/dispatch.rs +++ b/vendor/smb-server/src/dispatch.rs @@ -4,6 +4,7 @@ use std::sync::Arc; use crate::proto::auth::ntlm::Identity; use crate::proto::crypto::{PreauthIntegrity, sign}; +use crate::proto::crypto::encryption::{Smb3Encryption, CipherAlgorithm, TransformHeader}; use crate::proto::header::{ Command, HeaderTail, SMB2_FLAGS_ASYNC_COMMAND, SMB2_FLAGS_RELATED_OPERATIONS, SMB2_FLAGS_SERVER_TO_REDIR, SMB2_FLAGS_SIGNED, SMB2_HEADER_LEN, Smb2Header, @@ -82,6 +83,16 @@ pub async fn dispatch_frame( if let Some(bytes) = handle_smb1_multi_protocol(server, conn, frame).await { return Some(bytes); } + + // SMB3 encryption check: TRANSFORM_HEADER magic (0x534D4220 = "SMB ") + if frame.len() >= 4 { + let magic = u32::from_be_bytes([frame[0], frame[1], frame[2], frame[3]]); + if magic == 0x534D4220 { + // Encrypted packet - decrypt and process + return handle_encrypted_frame(server, conn, frame).await; + } + } + if frame.len() < SMB2_HEADER_LEN { warn!(len = frame.len(), "frame too short for SMB2 header"); return None; @@ -156,6 +167,94 @@ pub async fn dispatch_frame( Some(stitch_responses(conn, responses).await) } +/// Handle SMB3 encrypted frame (TRANSFORM_HEADER) +async fn handle_encrypted_frame( + server: &Arc, + conn: &Arc, + encrypted_frame: &[u8], +) -> Option> { + // Parse TRANSFORM_HEADER + let header = match TransformHeader::read_from_bytes(encrypted_frame) { + Ok(h) => h, + Err(e) => { + warn!(error = %e, "failed to parse TRANSFORM_HEADER"); + return None; + } + }; + + // Get session encryption key + let sessions = conn.sessions.read().await; + let session_arc = match sessions.get(&header.session_id).cloned() { + Some(s) => s, + None => { + warn!(session_id = header.session_id, "session not found for encrypted packet"); + return None; + } + }; + + let session = session_arc.read().await; + let encryption_enabled = session.encryption_enabled; + let encryption_key = session.encryption_key; + + if !encryption_enabled { + warn!("session does not have encryption enabled"); + return None; + } + + let encryption_key = match encryption_key { + Some(k) => k, + None => { + warn!("session has no encryption key"); + return None; + } + }; + + // Decrypt packet + let encryption = match Smb3Encryption::new(&encryption_key, CipherAlgorithm::Aes128Gcm) { + Ok(e) => e, + Err(e) => { + warn!(error = %e, "failed to create encryption context"); + return None; + } + }; + + let decrypted = match encryption.decrypt_packet(encrypted_frame) { + Ok(d) => d, + Err(e) => { + warn!(error = %e, "failed to decrypt packet"); + return None; + } + }; + + debug!(session_id = header.session_id, "decrypted SMB3 packet"); + + // Process decrypted frame (non-recursive: call dispatch_one directly) + if decrypted.len() < SMB2_HEADER_LEN { + warn!("decrypted frame too short"); + return None; + } + + let response = dispatch_one(server, conn, &decrypted).await; + + // Encrypt response if needed + if let Some(resp_bytes) = response { + if encryption_enabled { + let encrypted_response = match encryption.encrypt_packet(&resp_bytes, header.session_id) { + Ok(e) => e, + Err(e) => { + warn!(error = %e, "failed to encrypt response"); + return Some(resp_bytes); + } + }; + debug!("encrypted response packet"); + return Some(encrypted_response); + } + return Some(resp_bytes); + } + + None +} + fn inherit_related_context( sub_frame: &mut [u8], req_hdr: &mut Smb2Header,