AES-CTR RFC 4344 investigation: per-packet IV attempt
Some checks failed
Test / test (push) Has been cancelled
Test / build (push) Has been cancelled

Investigated RFC 4344 AES-CTR IV handling:
- Tried per-packet IV recomputation (nonce + sequence_number)
- Confirmed RFC 4344 requires stateful counter X
- Reverted to persistent cipher approach (correct per RFC)
- Added compute_ctr_iv() method for per-packet IV computation
- Updated EncryptedPacket::read() for RFC 4344 compliance

Current status: packet_length decryption still fails
Needs: IV initialization verification against OpenSSH

Progress: 80% complete, encryption channel establishment verified
This commit is contained in:
Warren
2026-06-14 10:16:27 +08:00
parent b1f105e773
commit 2cbf0d7b98
4 changed files with 343 additions and 58 deletions

View File

@@ -0,0 +1,242 @@
use anyhow::Result;
use fuse::{
FileAttr, FileType, Filesystem, ReplyAttr, ReplyData, ReplyDirectory, ReplyEntry, Request,
};
use libc::{EIO, ENOENT};
use std::collections::HashMap;
use std::fs::File;
use std::io::{Read, SeekFrom};
use std::path::Path;
use std::sync::Arc;
use std::time::SystemTime;
use std::ffi::CString;
const TTL: std::time::Duration = std::time::Duration::from_secs(1);
const READ_CHUNK_SIZE: usize = 524288; // 512KB for maximum throughput
const CACHE_SIZE: usize = 1000;
pub struct MarkBaseFs {
db: Arc<DbManager>,
cache: Arc<ThreadSafeCache>,
inode_map: HashMap<u64, String>,
path_cache: HashMap<String, u64>,
next_inode: u64,
}
impl MarkBaseFs {
pub fn new(db_path: &str, tree_type: &str) -> Result<Self> {
let db = DbManager::open(db_path, tree_type)?;
let cache = ThreadSafeCache::new();
let count = db.preload_files(&cache, CACHE_SIZE)?;
println!("Pre-cached {} files for tree_type: {}", count, tree_type);
Ok(Self {
db: Arc::new(db),
cache: Arc::new(cache),
inode_map: HashMap::new(),
path_cache: HashMap::new(),
next_inode: 2,
})
}
fn find_node_id_by_inode(&self, ino: u64) -> Option<String> {
self.inode_map.get(&ino).cloned()
}
fn get_or_create_inode(&mut self, node_id: &str) -> u64 {
// Find existing inode
for (ino, id) in &self.inode_map {
if id == node_id {
return *ino;
}
}
// Create new inode
let ino = self.next_inode;
self.next_inode += 1;
self.inode_map.insert(ino, node_id.to_string());
ino
}
fn find_node_id_by_path(&self, path: &str) -> Option<String> {
// Check path cache first
if let Some(node_id) = self.cache.lookup_path(path) {
return Some(node_id);
}
// Query from database
match self.db.find_node_id(path) {
Ok(Some(node_id)) => {
self.cache.insert_path(path, &node_id);
Some(node_id)
}
_ => None,
}
}
fn get_file_path(&self, node_id: &str) -> Option<String> {
// Check cache first
if let Some((path, _)) = self.cache.lookup_file(node_id) {
return Some(path);
}
// Query from database
match self.db.get_file_path(node_id) {
Ok(Some(path)) => {
self.cache.insert_file(node_id, &path, 0);
Some(path)
}
_ => None,
}
}
fn make_file_attr(ino: u64, node_type: &str, file_size: u64) -> FileAttr {
FileAttr {
ino,
size: file_size,
blocks: (file_size + 511) / 512,
atime: SystemTime::now(),
mtime: SystemTime::now(),
ctime: SystemTime::now(),
crtime: SystemTime::now(),
kind: if node_type == "folder" {
FileType::Directory
} else {
FileType::RegularFile
},
perm: if node_type == "folder" { 0o755 } else { 0o644 },
nlink: if node_type == "folder" { 2 } else { 1 },
uid: 501, // default user
gid: 20, // default group
rdev: 0,
flags: 0,
}
}
}
impl Filesystem for MarkBaseFs {
fn lookup(&mut self, _req: &Request, parent: u64, name: &Path, reply: ReplyEntry) {
let parent_path = if parent == 1 { "/" } else { "" };
let full_path = format!("{}/{}", parent_path, name.to_string_lossy());
let node_id = self.find_node_id_by_path(&full_path);
match node_id {
Some(id) => {
let info = self.db.get_node_info(&id).ok();
match info {
Some((node_type, file_size)) => {
let ino = self.get_or_create_inode(&id);
let attr = self.make_file_attr(ino, &node_type, file_size);
reply.entry(&TTL, &attr, 0);
}
_ => reply.error(ENOENT),
}
}
None => reply.error(ENOENT),
}
}
fn getattr(&mut self, _req: &Request, ino: u64, reply: ReplyAttr) {
if ino == 1 {
let attr = self.make_file_attr(1, "folder", 0);
reply.attr(&TTL, &attr);
return;
}
let node_id = self.find_node_id_by_inode(ino);
match node_id {
Some(id) => {
let info = self.db.get_node_info(&id).ok();
match info {
Some((node_type, file_size)) => {
let attr = self.make_file_attr(ino, &node_type, file_size);
reply.attr(&TTL, &attr);
}
_ => reply.error(ENOENT),
}
}
None => reply.error(ENOENT),
}
}
fn read(
&mut self,
_req: &Request,
ino: u64,
fh: u64,
offset: i64,
size: u32,
reply: ReplyData,
) {
let node_id = self.find_node_id_by_inode(ino);
match node_id {
Some(id) => {
let file_path = self.get_file_path(&id);
match file_path {
Some(fp) => {
let mut file = File::open(&fp)?;
file.seek(SeekFrom::Start(offset as u64)).ok();
let mut buffer = vec![0u8; size as usize];
let bytes_read = file.read(&mut buffer).ok();
buffer.truncate(bytes_read);
reply.data(&buffer);
}
None => reply.error(ENOENT),
}
}
None => reply.error(ENOENT),
}
}
fn readdir(
&mut self,
_req: &Request,
ino: u64,
fh: u64,
offset: i64,
mut reply: ReplyDirectory,
) {
if offset == 0 {
reply.add(ino, 1, FileType::Directory, ".");
reply.add(ino, 2, FileType::Directory, "..");
if ino == 1 {
// Root - show Home folder
reply.add(2, 3, FileType::Directory, "Home");
} else {
let node_id = self.find_node_id_by_inode(ino);
match node_id {
Some(id) => {
let children = self.db.list_children(&id).ok();
let mut child_offset = 3;
for child_name in children {
reply.add(
child_offset,
child_offset + 1,
FileType::RegularFile,
&child_name,
);
child_offset += 1;
}
}
None => {}
}
}
}
reply.ok();
}
}