Phase 1.3: SMB3 packet encryption handling complete
Some checks failed
Test / test (push) Has been cancelled
Test / build (push) Has been cancelled

- 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
This commit is contained in:
Warren
2026-06-22 03:18:22 +08:00
parent 98239c09d4
commit 382ea2e28b

View File

@@ -4,6 +4,7 @@ use std::sync::Arc;
use crate::proto::auth::ntlm::Identity; use crate::proto::auth::ntlm::Identity;
use crate::proto::crypto::{PreauthIntegrity, sign}; use crate::proto::crypto::{PreauthIntegrity, sign};
use crate::proto::crypto::encryption::{Smb3Encryption, CipherAlgorithm, TransformHeader};
use crate::proto::header::{ use crate::proto::header::{
Command, HeaderTail, SMB2_FLAGS_ASYNC_COMMAND, SMB2_FLAGS_RELATED_OPERATIONS, Command, HeaderTail, SMB2_FLAGS_ASYNC_COMMAND, SMB2_FLAGS_RELATED_OPERATIONS,
SMB2_FLAGS_SERVER_TO_REDIR, SMB2_FLAGS_SIGNED, SMB2_HEADER_LEN, Smb2Header, 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 { if let Some(bytes) = handle_smb1_multi_protocol(server, conn, frame).await {
return Some(bytes); 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 { if frame.len() < SMB2_HEADER_LEN {
warn!(len = frame.len(), "frame too short for SMB2 header"); warn!(len = frame.len(), "frame too short for SMB2 header");
return None; return None;
@@ -156,6 +167,94 @@ pub async fn dispatch_frame(
Some(stitch_responses(conn, responses).await) Some(stitch_responses(conn, responses).await)
} }
/// Handle SMB3 encrypted frame (TRANSFORM_HEADER)
async fn handle_encrypted_frame(
server: &Arc<ServerState>,
conn: &Arc<Connection>,
encrypted_frame: &[u8],
) -> Option<Vec<u8>> {
// 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( fn inherit_related_context(
sub_frame: &mut [u8], sub_frame: &mut [u8],
req_hdr: &mut Smb2Header, req_hdr: &mut Smb2Header,