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)
This commit is contained in:
@@ -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<Aes128>; // AES-128-CTR(16字节密钥)
|
||||
type HmacSha256 = Hmac<Sha256>;
|
||||
// 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<u8>, // session identifier (exchange hash)
|
||||
pub encryption_key_ctos: Vec<u8>, // 客户端→服务器加密密钥
|
||||
pub encryption_key_stoc: Vec<u8>, // 服务器→客户端加密密钥
|
||||
pub mac_key_ctos: Vec<u8>, // 客户端→服务器MAC密钥
|
||||
pub mac_key_stoc: Vec<u8>, // 服务器→客户端MAC密钥
|
||||
pub mac_key_ctos: Vec<u8>, // 客户端→服务器MAC密钥(仅用于AES-CTR)
|
||||
pub mac_key_stoc: Vec<u8>, // 服务器→客户端MAC密钥(仅用于AES-CTR)
|
||||
pub iv_ctos: Vec<u8>, // 客户端→服务器IV
|
||||
pub iv_stoc: Vec<u8>, // 服务器→客户端IV
|
||||
pub sequence_number_ctos: u32, // 客户端→服务器序列号
|
||||
pub sequence_number_stoc: u32, // 服务器→客户端序列号
|
||||
pub cipher_ctos: Option<Aes128Ctr>, // 客户端→服务器cipher实例(持久化)
|
||||
pub cipher_stoc: Option<Aes128Ctr>, // 服务器→客户端cipher实例(持久化)
|
||||
pub cipher_ctos: Option<Aes128Ctr>, // 客户端→服务器cipher实例(持久化,AES-CTR)
|
||||
pub cipher_stoc: Option<Aes128Ctr>, // 服务器→客户端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<u8> {
|
||||
@@ -158,8 +206,8 @@ impl EncryptionContext {
|
||||
mac_key: &[u8],
|
||||
) -> Result<Vec<u8>> {
|
||||
// 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 = <HmacSha256 as hmac::Mac>::new_from_slice(mac_key)?;
|
||||
|
||||
// OpenSSH MAC格式:sequence_number + data
|
||||
mac.update(&sequence_number.to_be_bytes());
|
||||
|
||||
Reference in New Issue
Block a user