diff --git a/data/auth.sqlite b/data/auth.sqlite index e75155b..3e7f0cd 100644 Binary files a/data/auth.sqlite and b/data/auth.sqlite differ diff --git a/markbase-core/src/ssh_server/kex_exchange.rs b/markbase-core/src/ssh_server/kex_exchange.rs index 47fe19f..5474fbe 100644 --- a/markbase-core/src/ssh_server/kex_exchange.rs +++ b/markbase-core/src/ssh_server/kex_exchange.rs @@ -209,11 +209,15 @@ impl KexExchangeHandler { let mut hasher = Sha256::new(); // RFC 4253 Section 7: V_C and V_S are version strings (without \r\n based on testing) - hasher.update(&(client_version.len() as u32).to_be_bytes()); + let vc_ssh_string = &(client_version.len() as u32).to_be_bytes(); + hasher.update(vc_ssh_string); hasher.update(client_version.as_bytes()); + info!(" Exchange hash component V_C: len={} bytes=[{:?}] data=[{:?}]", 4+client_version.len(), vc_ssh_string, client_version.as_bytes()); - hasher.update(&(server_version.len() as u32).to_be_bytes()); + let vs_ssh_string = &(server_version.len() as u32).to_be_bytes(); + hasher.update(vs_ssh_string); hasher.update(server_version.as_bytes()); + info!(" Exchange hash component V_S: len={} bytes=[{:?}] data=[{:?}]", 4+server_version.len(), vs_ssh_string, server_version.as_bytes()); // OpenSSH kexgex.c: "kexinit messages: fake header: len+SSH2_MSG_KEXINIT" // KEXINIT payload should NOT include SSH_MSG_KEXINIT type byte @@ -227,25 +231,35 @@ impl KexExchangeHandler { info!("I_S (server KEXINIT without type byte): {} bytes", server_kexinit_without_type.len()); // Exchange hash: uint32(len+1) + uint8(SSH_MSG_KEXINIT) + payload_without_type - hasher.update(&((client_kexinit_without_type.len() + 1) as u32).to_be_bytes()); + let ic_len_bytes = &((client_kexinit_without_type.len() + 1) as u32).to_be_bytes(); + hasher.update(ic_len_bytes); hasher.update(&[20]); // SSH_MSG_KEXINIT type byte hasher.update(client_kexinit_without_type); + info!(" Exchange hash component I_C: len={} bytes=[{:?}] type=[20] payload_len={} (first 8 bytes=[{:?}])", 4+1+client_kexinit_without_type.len(), ic_len_bytes, client_kexinit_without_type.len(), &client_kexinit_without_type[..std::cmp::min(8, client_kexinit_without_type.len())]); - hasher.update(&((server_kexinit_without_type.len() + 1) as u32).to_be_bytes()); + let is_len_bytes = &((server_kexinit_without_type.len() + 1) as u32).to_be_bytes(); + hasher.update(is_len_bytes); hasher.update(&[20]); // SSH_MSG_KEXINIT type byte hasher.update(server_kexinit_without_type); + info!(" Exchange hash component I_S: len={} bytes=[{:?}] type=[20] payload_len={} (first 8 bytes=[{:?}])", 4+1+server_kexinit_without_type.len(), is_len_bytes, server_kexinit_without_type.len(), &server_kexinit_without_type[..std::cmp::min(8, server_kexinit_without_type.len())]); - hasher.update(&(host_key_blob.len() as u32).to_be_bytes()); + let ks_len_bytes = &(host_key_blob.len() as u32).to_be_bytes(); + hasher.update(ks_len_bytes); hasher.update(host_key_blob); + info!(" Exchange hash component K_S: len={} bytes=[{:?}] blob_len={} (full=[{:?}])", 4+host_key_blob.len(), ks_len_bytes, host_key_blob.len(), host_key_blob); - hasher.update(&(client_public_key.len() as u32).to_be_bytes()); + let qc_len_bytes = &(client_public_key.len() as u32).to_be_bytes(); + hasher.update(qc_len_bytes); hasher.update(client_public_key); + info!(" Exchange hash component Q_C: len={} bytes=[{:?}] key=[{:?}]", 4+client_public_key.len(), qc_len_bytes, client_public_key); - hasher.update(&(server_public_key.len() as u32).to_be_bytes()); + let qs_len_bytes = &(server_public_key.len() as u32).to_be_bytes(); + hasher.update(qs_len_bytes); hasher.update(server_public_key); + info!(" Exchange hash component Q_S: len={} bytes=[{:?}] key=[{:?}]", 4+server_public_key.len(), qs_len_bytes, server_public_key); info!("Exchange hash components:"); - info!(" shared_secret raw ({} bytes): {:?}", shared_secret.len(), &shared_secret[..std::cmp::min(8, shared_secret.len())]); + info!(" shared_secret raw full (32 bytes): {:?}", shared_secret); // RFC 8731 Section 3.1: X25519 output is little-endian // OpenSSH sshbuf_put_bignum2_bytes() uses bytes DIRECTLY (no reversal) @@ -260,7 +274,7 @@ impl KexExchangeHandler { } let trimmed_shared_secret = &shared_secret[start..]; - info!(" shared_secret after removing leading zeros ({} bytes): {:?}", trimmed_shared_secret.len(), &trimmed_shared_secret[..std::cmp::min(8, trimmed_shared_secret.len())]); + info!(" shared_secret after removing leading zeros ({} bytes): {:?}", trimmed_shared_secret.len(), trimmed_shared_secret); let mpint_shared_secret_data = if trimmed_shared_secret.len() > 0 && trimmed_shared_secret[0] >= 0x80 { let mut mpint = vec![0u8]; @@ -274,8 +288,10 @@ impl KexExchangeHandler { info!(" mpint_shared_secret_data ({} bytes): {:?}", mpint_shared_secret_data.len(), &mpint_shared_secret_data[..std::cmp::min(8, mpint_shared_secret_data.len())]); // mpint格式 = uint32(length) + mpint_data - hasher.update(&(mpint_shared_secret_data.len() as u32).to_be_bytes()); + let mpint_len_bytes = &(mpint_shared_secret_data.len() as u32).to_be_bytes(); + hasher.update(mpint_len_bytes); hasher.update(&mpint_shared_secret_data); + info!(" Exchange hash component K (shared secret mpint): len={} bytes=[{:?}] data_len={} (first 8 bytes=[{:?}])", 4+mpint_shared_secret_data.len(), mpint_len_bytes, mpint_shared_secret_data.len(), &mpint_shared_secret_data[..std::cmp::min(8, mpint_shared_secret_data.len())]); Ok(hasher.finalize().to_vec()) }