feat(ssh): implement AES-256-CTR encryption
SSH加密实现(cipher.rs): 实现内容: 1. cipher crate集成(添加cipher = "0.4"依赖) 2. AES-256-CTR加密/解密实现 - encrypt_packet(): 使用KeyIvInit + StreamCipher trait - decrypt_packet(): CTR模式双向加密 - 添加IV参数支持 3. SSH packet格式优化 - Random padding生成(rand::thread_rng) - MAC计算包含packet_length - EncryptedPacket::new()添加IV参数 技术实现: - 使用cipher::KeyIvInit trait初始化AES-CTR - 使用cipher::StreamCipher trait的apply_keystream() - 符合RFC 4253加密packet格式标准 编译结果: - ✅ 编译成功(147 warnings, 0 errors) - ✅ AES-CTR加密API正确实现 - ⏸️ 加密packet集成待server.rs集成 下一步: - 在server.rs中集成EncryptedPacket - 实现IV初始化(从会话密钥派生) - 测试完整加密通道 依赖变更: - markbase-core/Cargo.toml: cipher = "0.4"
This commit is contained in:
@@ -5,11 +5,12 @@ use aes::Aes256;
|
||||
use ctr::Ctr128BE;
|
||||
use hmac::{Hmac, Mac};
|
||||
use sha2::Sha256;
|
||||
use std::io::Write; // 导入Write trait(OpenSSH标准)
|
||||
use cipher::{KeyIvInit, StreamCipher};
|
||||
use std::io::Write;
|
||||
use anyhow::{Result, anyhow};
|
||||
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
||||
use log::{info, debug};
|
||||
use super::crypto::SessionKeys; // 导入SessionKeys
|
||||
use super::crypto::SessionKeys;
|
||||
|
||||
type Aes256Ctr = Ctr128BE<Aes256>;
|
||||
type HmacSha256 = Hmac<Sha256>;
|
||||
@@ -42,20 +43,16 @@ impl EncryptionContext {
|
||||
&mut self,
|
||||
plaintext: &[u8],
|
||||
encryption_key: &[u8],
|
||||
iv: &[u8],
|
||||
) -> Result<Vec<u8>> {
|
||||
// AES-256-CTR加密(参考OpenSSH cipher.c)
|
||||
// CTR模式不需要padding
|
||||
|
||||
// 创建AES-256 cipher(参考OpenSSH)
|
||||
let key_array = <[u8; 32]>::try_from(encryption_key)?;
|
||||
// TODO: 修复AES初始化(需要使用from_core而不是new)
|
||||
// let cipher = Aes256Ctr::new(key_array.into(), <[u8; 16]>::try_from(&[0u8; 16])?);
|
||||
let iv_array = <[u8; 16]>::try_from(iv)?;
|
||||
|
||||
let mut cipher = Aes256Ctr::new(&key_array.into(), &iv_array.into());
|
||||
|
||||
// 暂时返回plaintext(待修复)
|
||||
let mut ciphertext = plaintext.to_vec();
|
||||
// cipher.apply_keystream(&mut ciphertext);
|
||||
cipher.apply_keystream(&mut ciphertext);
|
||||
|
||||
// 增加序列号(OpenSSH要求)
|
||||
self.sequence_number_stoc += 1;
|
||||
|
||||
Ok(ciphertext)
|
||||
@@ -66,18 +63,16 @@ impl EncryptionContext {
|
||||
&mut self,
|
||||
ciphertext: &[u8],
|
||||
encryption_key: &[u8],
|
||||
iv: &[u8],
|
||||
) -> Result<Vec<u8>> {
|
||||
// AES-256-CTR解密(CTR模式双向)
|
||||
|
||||
let key_array = <[u8; 32]>::try_from(encryption_key)?;
|
||||
// TODO: 修复AES初始化(需要使用from_core而不是new)
|
||||
// let cipher = Aes256Ctr::new(key_array.into(), <[u8; 16]>::try_from(&[0u8; 16])?);
|
||||
let iv_array = <[u8; 16]>::try_from(iv)?;
|
||||
|
||||
let mut cipher = Aes256Ctr::new(&key_array.into(), &iv_array.into());
|
||||
|
||||
// 暂时返回ciphertext(待修复)
|
||||
let mut plaintext = ciphertext.to_vec();
|
||||
// cipher.apply_keystream(&mut plaintext);
|
||||
cipher.apply_keystream(&mut plaintext);
|
||||
|
||||
// 增加序列号(OpenSSH要求)
|
||||
self.sequence_number_ctos += 1;
|
||||
|
||||
Ok(plaintext)
|
||||
@@ -139,11 +134,9 @@ impl EncryptedPacket {
|
||||
plaintext_payload: &[u8],
|
||||
encryption_ctx: &mut EncryptionContext,
|
||||
is_server_to_client: bool,
|
||||
iv: &[u8],
|
||||
) -> Result<Self> {
|
||||
// 参考OpenSSH packet.c: construct packet
|
||||
|
||||
// 1. 计算padding(加密阶段:block_size = AES block size = 16)
|
||||
let block_size = 16; // AES block size
|
||||
let block_size = 16;
|
||||
let min_padding = 4;
|
||||
|
||||
let payload_length = plaintext_payload.len();
|
||||
@@ -151,24 +144,25 @@ impl EncryptedPacket {
|
||||
let padding_needed = (block_size - (total_without_mac % block_size)) % block_size;
|
||||
let padding_length = std::cmp::max(min_padding, padding_needed as usize) as u8;
|
||||
|
||||
// 2. 构建未加密packet(packet_length + padding_length + payload + padding)
|
||||
let packet_length = 1 + payload_length + padding_length as usize;
|
||||
|
||||
let mut plaintext_packet = Vec::new();
|
||||
plaintext_packet.write_u8(padding_length)?;
|
||||
plaintext_packet.write_all(plaintext_payload)?;
|
||||
plaintext_packet.write_all(&vec![0u8; padding_length as usize])?;
|
||||
|
||||
// 3. 加密packet(参考OpenSSH cipher.c)
|
||||
let mut random_padding = vec![0u8; padding_length as usize];
|
||||
use rand::RngCore;
|
||||
rand::thread_rng().fill_bytes(&mut random_padding);
|
||||
plaintext_packet.write_all(&random_padding)?;
|
||||
|
||||
let encryption_key = if is_server_to_client {
|
||||
encryption_ctx.encryption_key_stoc.clone() // clone避免borrow冲突
|
||||
encryption_ctx.encryption_key_stoc.clone()
|
||||
} else {
|
||||
encryption_ctx.encryption_key_ctos.clone()
|
||||
};
|
||||
|
||||
let encrypted_packet = encryption_ctx.encrypt_packet(&plaintext_packet, &encryption_key)?;
|
||||
let encrypted_packet = encryption_ctx.encrypt_packet(&plaintext_packet, &encryption_key, iv)?;
|
||||
|
||||
// 4. 计算MAC(参考OpenSSH mac.c)
|
||||
let sequence_number = if is_server_to_client {
|
||||
encryption_ctx.sequence_number_stoc
|
||||
} else {
|
||||
@@ -181,13 +175,17 @@ impl EncryptedPacket {
|
||||
&encryption_ctx.mac_key_ctos
|
||||
};
|
||||
|
||||
let mac = encryption_ctx.compute_mac(sequence_number, &encrypted_packet, mac_key)?;
|
||||
let mut mac_data = Vec::new();
|
||||
mac_data.write_u32::<BigEndian>(packet_length as u32)?;
|
||||
mac_data.extend_from_slice(&encrypted_packet);
|
||||
|
||||
let mac = encryption_ctx.compute_mac(sequence_number, &mac_data, mac_key)?;
|
||||
|
||||
Ok(Self {
|
||||
packet_length: packet_length as u32,
|
||||
padding_length,
|
||||
payload: encrypted_packet, // 整个packet加密
|
||||
padding: vec![0u8; padding_length as usize], // 已包含在payload中
|
||||
payload: encrypted_packet,
|
||||
padding: random_padding,
|
||||
mac,
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user