Remove dead code: compute_exchange_hash + write_ssh_mpint_to_hash in kex_complete.rs (replaced by kex_exchange.rs version)
This commit is contained in:
@@ -2,12 +2,11 @@
|
|||||||
// 参考OpenSSH kex.c: complete implementation
|
// 参考OpenSSH kex.c: complete implementation
|
||||||
|
|
||||||
use crate::ssh_server::crypto::SessionKeys;
|
use crate::ssh_server::crypto::SessionKeys;
|
||||||
use crate::ssh_server::kex::{KexProposal, KexResult};
|
use crate::ssh_server::kex::KexResult;
|
||||||
use crate::ssh_server::kex_exchange::KexExchangeHandler;
|
use crate::ssh_server::kex_exchange::KexExchangeHandler;
|
||||||
use crate::ssh_server::packet::{PacketType, SshPacket};
|
use crate::ssh_server::packet::{PacketType, SshPacket};
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use log::info;
|
use log::info;
|
||||||
use sha2::{Digest, Sha256};
|
|
||||||
|
|
||||||
/// SSH密钥交换完整状态管理(参考OpenSSH struct kex)
|
/// SSH密钥交换完整状态管理(参考OpenSSH struct kex)
|
||||||
pub struct KexState {
|
pub struct KexState {
|
||||||
@@ -74,54 +73,6 @@ impl KexState {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 计算Exchange Hash(参考OpenSSH kex.c: kex_hash())
|
|
||||||
/// H = SHA256(V_C || V_S || I_C || I_S || K_S || K_C || K_S || shared_secret)
|
|
||||||
pub fn compute_exchange_hash(
|
|
||||||
&self,
|
|
||||||
shared_secret: &[u8],
|
|
||||||
server_host_key_blob: &[u8],
|
|
||||||
client_public_key: &[u8],
|
|
||||||
server_public_key: &[u8],
|
|
||||||
) -> Result<Vec<u8>> {
|
|
||||||
// 参考OpenSSH kex.c: kex_hash()
|
|
||||||
let mut hasher = Sha256::new();
|
|
||||||
|
|
||||||
// V_C: 客户端版本字符串(SSH string格式)
|
|
||||||
write_ssh_string_to_hash(&mut hasher, &self.client_version)?;
|
|
||||||
|
|
||||||
// V_S: 服务器版本字符串(SSH string格式)
|
|
||||||
write_ssh_string_to_hash(&mut hasher, &self.server_version)?;
|
|
||||||
|
|
||||||
// OpenSSH kexgex.c: "kexinit messages: fake header: len+SSH2_MSG_KEXINIT"
|
|
||||||
// Remove SSH_MSG_KEXINIT type byte from payloads and prepend it in exchange hash
|
|
||||||
|
|
||||||
let client_kexinit_without_type = &self.client_kexinit_payload[1..];
|
|
||||||
let server_kexinit_without_type = &self.server_kexinit_payload[1..];
|
|
||||||
|
|
||||||
hasher.update(((client_kexinit_without_type.len() + 1) as u32).to_be_bytes());
|
|
||||||
hasher.update([20]); // SSH_MSG_KEXINIT type byte
|
|
||||||
hasher.update(client_kexinit_without_type);
|
|
||||||
|
|
||||||
hasher.update(((server_kexinit_without_type.len() + 1) as u32).to_be_bytes());
|
|
||||||
hasher.update([20]); // SSH_MSG_KEXINIT type byte
|
|
||||||
hasher.update(server_kexinit_without_type);
|
|
||||||
|
|
||||||
// K_S: 服务器主机密钥blob(SSH string格式)
|
|
||||||
hasher.update(server_host_key_blob);
|
|
||||||
|
|
||||||
// K_C: 客户端Curve25519公钥(SSH string格式)
|
|
||||||
write_ssh_bytes_to_hash(&mut hasher, client_public_key)?;
|
|
||||||
|
|
||||||
// K_S: 服务器Curve25519公钥(SSH string格式)
|
|
||||||
write_ssh_bytes_to_hash(&mut hasher, server_public_key)?;
|
|
||||||
|
|
||||||
// K: 共享密钥(SSH mpint格式)
|
|
||||||
// OpenSSH要求:去掉前导零
|
|
||||||
write_ssh_mpint_to_hash(&mut hasher, shared_secret)?;
|
|
||||||
|
|
||||||
Ok(hasher.finalize().to_vec())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 处理SSH_MSG_NEWKEYS(参考OpenSSH kex.c: kex_input_newkeys())
|
/// 处理SSH_MSG_NEWKEYS(参考OpenSSH kex.c: kex_input_newkeys())
|
||||||
pub fn handle_newkeys(&mut self, packet: &SshPacket) -> Result<()> {
|
pub fn handle_newkeys(&mut self, packet: &SshPacket) -> Result<()> {
|
||||||
info!("Processing SSH_MSG_NEWKEYS");
|
info!("Processing SSH_MSG_NEWKEYS");
|
||||||
@@ -159,72 +110,10 @@ impl KexState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// SSH string写入到hash(辅助函数)
|
|
||||||
fn write_ssh_string_to_hash(hasher: &mut Sha256, s: &str) -> Result<()> {
|
|
||||||
hasher.update((s.len() as u32).to_be_bytes());
|
|
||||||
hasher.update(s.as_bytes());
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// SSH bytes写入到hash(辅助函数)
|
|
||||||
fn write_ssh_bytes_to_hash(hasher: &mut Sha256, bytes: &[u8]) -> Result<()> {
|
|
||||||
hasher.update((bytes.len() as u32).to_be_bytes());
|
|
||||||
hasher.update(bytes);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// SSH mpint写入到hash(参考OpenSSH sshbuf_put_mpint())
|
|
||||||
fn write_ssh_mpint_to_hash(hasher: &mut Sha256, bytes: &[u8]) -> Result<()> {
|
|
||||||
// OpenSSH要求:去掉前导零(如果最高位为1)
|
|
||||||
let mpint_bytes = if !bytes.is_empty() && bytes[0] >= 0x80 {
|
|
||||||
// 需要添加前导零(避免负数)
|
|
||||||
let mut mpint = vec![0u8];
|
|
||||||
mpint.extend_from_slice(bytes);
|
|
||||||
mpint
|
|
||||||
} else {
|
|
||||||
bytes.to_vec()
|
|
||||||
};
|
|
||||||
|
|
||||||
hasher.update((mpint_bytes.len() as u32).to_be_bytes());
|
|
||||||
hasher.update(&mpint_bytes);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::ssh_server::kex::{KexProposal, KexResult};
|
||||||
#[test]
|
|
||||||
fn test_exchange_hash_computation() {
|
|
||||||
let kex_result = KexResult::choose_algorithms(
|
|
||||||
&KexProposal::server_default(),
|
|
||||||
&KexProposal::client_default(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let mut state = KexState::new(
|
|
||||||
"SSH-2.0-OpenSSH_10.2".to_string(),
|
|
||||||
"SSH-2.0-MarkBaseSSH_1.0".to_string(),
|
|
||||||
kex_result,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Set minimal KEXINIT payloads (need at least 1 byte for packet type)
|
|
||||||
state.client_kexinit_payload = vec![20u8]; // SSH_MSG_KEXINIT type byte
|
|
||||||
state.server_kexinit_payload = vec![20u8]; // SSH_MSG_KEXINIT type byte
|
|
||||||
|
|
||||||
let shared_secret = vec![0u8; 32];
|
|
||||||
let host_key = vec![0u8; 32];
|
|
||||||
let client_pub = vec![0u8; 32];
|
|
||||||
let server_pub = vec![0u8; 32];
|
|
||||||
|
|
||||||
let hash = state
|
|
||||||
.compute_exchange_hash(&shared_secret, &host_key, &client_pub, &server_pub)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(hash.len(), 32); // SHA256输出32字节
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_newkeys_handling() {
|
fn test_newkeys_handling() {
|
||||||
|
|||||||
Reference in New Issue
Block a user