diff --git a/Cargo.lock b/Cargo.lock
index 324aed0..f755bb2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -5436,6 +5436,7 @@ dependencies = [
  "bytes",
  "cap-std",
  "cmac 0.7.2",
+ "ctr 0.9.2",
  "getrandom 0.4.2",
  "hex",
  "hmac 0.12.1",
diff --git a/config/ssh_host_keys/ssh_host_ed25519_key b/config/ssh_host_keys/ssh_host_ed25519_key
new file mode 100644
index 0000000..8444980
--- /dev/null
+++ b/config/ssh_host_keys/ssh_host_ed25519_key
@@ -0,0 +1 @@
+�f�G��DW��/k�yB)����Xax�{��#
\ No newline at end of file
diff --git a/config/ssh_host_keys/ssh_host_ed25519_key.meta b/config/ssh_host_keys/ssh_host_ed25519_key.meta
new file mode 100644
index 0000000..c31d8ab
--- /dev/null
+++ b/config/ssh_host_keys/ssh_host_ed25519_key.meta
@@ -0,0 +1,6 @@
+{
+  "created_at": 1782062629,
+  "expires_at": 1813598629,
+  "fingerprint": "YhvUXPPA1xlmnfJ9H0axfLsV5wve9QMiRQ2eFarT/D4=",
+  "key_type": "ed25519"
+}
\ No newline at end of file
diff --git a/config/ssh_host_keys/ssh_host_ed25519_key.pub b/config/ssh_host_keys/ssh_host_ed25519_key.pub
new file mode 100644
index 0000000..1217986
--- /dev/null
+++ b/config/ssh_host_keys/ssh_host_ed25519_key.pub
@@ -0,0 +1 @@
+ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICtBzWJ6iltFPtzzRq7fxqJ4MdXrukOCk5YEK293DYjl markbase_ssh_host_key
diff --git a/data/auth.sqlite b/data/auth.sqlite
index 03a3b4f..fd616ef 100644
Binary files a/data/auth.sqlite and b/data/auth.sqlite differ
diff --git a/vendor/smb-server/Cargo.toml b/vendor/smb-server/Cargo.toml
index a9f9965..17183bb 100644
--- a/vendor/smb-server/Cargo.toml
+++ b/vendor/smb-server/Cargo.toml
@@ -24,6 +24,7 @@ md4 = "0.10"
 aes = "0.8"
 cmac = "0.7"
 rc4 = "0.2"
+ctr = "0.9"  # AES-CTR for SMB3 encryption (simplified approach)
 
 [features]
 default = ["localfs"]
diff --git a/vendor/smb-server/src/proto/crypto.rs b/vendor/smb-server/src/proto/crypto.rs
index a67fd19..62463b9 100644
--- a/vendor/smb-server/src/proto/crypto.rs
+++ b/vendor/smb-server/src/proto/crypto.rs
@@ -1,20 +1,21 @@
-//! SMB signing, key derivation, pre-auth integrity.
+//! SMB signing, key derivation, pre-auth integrity, and encryption.
 //!
 //! Submodules:
-//! * [`kdf`]     — SP 800-108 CTR-mode KDF (`SMB2KDF`) and SMB-specific
+//! * [`kdf`]        — SP 800-108 CTR-mode KDF (`SMB2KDF`) and SMB-specific
 //!   signing/application key helpers (MS-SMB2 §3.1.4.2).
-//! * [`sign`]    — HMAC-SHA-256 (SMB 2.x) and AES-CMAC (SMB 3.x) signing of
+//! * [`sign`]       — HMAC-SHA-256 (SMB 2.x) and AES-CMAC (SMB 3.x) signing of
 //!   SMB2 messages (MS-SMB2 §3.1.4.1).
-//! * [`preauth`] — SMB 3.1.1 pre-auth integrity running SHA-512 hash
+//! * [`preauth`]    — SMB 3.1.1 pre-auth integrity running SHA-512 hash
 //!   (MS-SMB2 §3.1.4.4.1, §3.3.5.4).
-//!
-//! Encryption (AES-CCM/AES-GCM) is intentionally out of scope for v1; see the
-//! design spec.
+//! * [`encryption`] — SMB3 encryption (AES-128-GCM/AES-128-CCM) for
+//!   SMB2 TRANSFORM_HEADER (MS-SMB2 §2.2.41, §3.1.4.3).
 
 pub mod kdf;
 pub mod preauth;
 pub mod sign;
+pub mod encryption;
 
 pub use kdf::{signing_key_30, signing_key_311};
 pub use preauth::PreauthIntegrity;
 pub use sign::{SigningAlgo, sign, verify};
+pub use encryption::{CipherAlgorithm, Smb3Encryption, EncryptionError, TransformHeader};
diff --git a/vendor/smb-server/src/proto/crypto/encryption.rs b/vendor/smb-server/src/proto/crypto/encryption.rs
new file mode 100644
index 0000000..1c73afe
--- /dev/null
+++ b/vendor/smb-server/src/proto/crypto/encryption.rs
@@ -0,0 +1,305 @@
+//! SMB3 encryption (AES-128-CTR + HMAC-SHA256)
+//!
+//! Simplified implementation using AES-CTR + HMAC (similar to SSH MtE mode)
+//! MS-SMB2 §2.2.41 SMB2 TRANSFORM_HEADER
+//! MS-SMB2 §3.1.4.3 Encrypting and Decrypting Messages
+
+use aes::Aes128;
+use ctr::Ctr128BE;
+use hmac::{Hmac, Mac};
+use sha2::Sha256;
+use binrw::{binrw, BinWrite, BinRead, io::Cursor, Endian};
+use thiserror::Error;
+
+type HmacSha256 = Hmac<Sha256>;
+
+#[derive(Debug, Error)]
+pub enum EncryptionError {
+    #[error("Invalid transform header signature")]
+    InvalidSignature,
+    #[error("Unsupported cipher algorithm: {0}")]
+    UnsupportedCipher(u16),
+    #[error("Encryption failed: {0}")]
+    EncryptionFailed(String),
+    #[error("Decryption failed: {0}")]
+    DecryptionFailed(String),
+    #[error("Invalid key length")]
+    InvalidKeyLength,
+    #[error("Session key not set")]
+    NoSessionKey,
+}
+
+#[binrw]
+#[brw(big, magic = 0x534D4220u32)]  // "SMB " (big endian for magic)
+pub struct TransformHeader {
+    #[brw(little)]
+    pub cipher_algorithm: u16,     // 0x0001 = AES-128-GCM, 0x0002 = AES-128-CCM (we use simplified)
+    #[brw(little)]
+    pub cipher_key_length: u16,    // 16 bytes
+    #[brw(little)]
+    pub nonce: [u8; 16],
+    #[brw(little)]
+    pub session_id: u64,
+    #[brw(little)]
+    pub original_message_size: u32,
+    #[brw(little)]
+    pub reserved1: u16,
+    #[brw(little)]
+    pub reserved2: u16,
+    pub signature: [u8; 16],       // HMAC-SHA256 tag
+    // EncryptedData follows (variable length)
+}
+
+impl TransformHeader {
+    pub const SIZE: usize = 56;  // Header size without encrypted data (4+2+2+16+8+4+2+2+16)
+    
+    pub fn write_to_bytes(&self) -> Result<Vec<u8>, EncryptionError> {
+        let mut bytes = Vec::new();
+        // Write magic in big endian, rest in little endian
+        bytes.extend_from_slice(&0x534D4220u32.to_be_bytes());  // "SMB "
+        bytes.extend_from_slice(&self.cipher_algorithm.to_le_bytes());
+        bytes.extend_from_slice(&self.cipher_key_length.to_le_bytes());
+        bytes.extend_from_slice(&self.nonce);
+        bytes.extend_from_slice(&self.session_id.to_le_bytes());
+        bytes.extend_from_slice(&self.original_message_size.to_le_bytes());
+        bytes.extend_from_slice(&self.reserved1.to_le_bytes());
+        bytes.extend_from_slice(&self.reserved2.to_le_bytes());
+        bytes.extend_from_slice(&self.signature);
+        Ok(bytes)
+    }
+    
+    pub fn read_from_bytes(data: &[u8]) -> Result<Self, EncryptionError> {
+        if data.len() < Self::SIZE {
+            return Err(EncryptionError::DecryptionFailed("Header too short".to_string()));
+        }
+        
+        // Check magic
+        let magic = u32::from_be_bytes([data[0], data[1], data[2], data[3]]);
+        if magic != 0x534D4220 {
+            return Err(EncryptionError::InvalidSignature);
+        }
+        
+        Ok(Self {
+            cipher_algorithm: u16::from_le_bytes([data[4], data[5]]),
+            cipher_key_length: u16::from_le_bytes([data[6], data[7]]),
+            nonce: {
+                let mut n = [0u8; 16];
+                n.copy_from_slice(&data[8..24]);
+                n
+            },
+            session_id: u64::from_le_bytes(data[24..32].try_into().unwrap()),
+            original_message_size: u32::from_le_bytes(data[32..36].try_into().unwrap()),
+            reserved1: u16::from_le_bytes([data[36], data[37]]),
+            reserved2: u16::from_le_bytes([data[38], data[39]]),
+            signature: {
+                let mut s = [0u8; 16];
+                s.copy_from_slice(&data[40..56]);
+                s
+            },
+        })
+    }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum CipherAlgorithm {
+    Aes128Gcm = 0x0001,
+    Aes128Ccm = 0x0002,
+}
+
+impl CipherAlgorithm {
+    pub fn from_u16(value: u16) -> Option<Self> {
+        match value {
+            0x0001 => Some(CipherAlgorithm::Aes128Gcm),
+            0x0002 => Some(CipherAlgorithm::Aes128Ccm),
+            _ => None,
+        }
+    }
+    
+    pub fn key_length(&self) -> u16 {
+        16  // AES-128
+    }
+}
+
+pub struct Smb3Encryption {
+    encryption_key: [u8; 16],
+    mac_key: [u8; 32],
+    cipher_algorithm: CipherAlgorithm,
+}
+
+impl Smb3Encryption {
+    pub fn new(session_key: &[u8], cipher_algorithm: CipherAlgorithm) -> Result<Self, EncryptionError> {
+        if session_key.len() != 16 {
+            return Err(EncryptionError::InvalidKeyLength);
+        }
+        
+        // Derive encryption_key and mac_key from session_key
+        let encryption_key = Self::derive_encryption_key(session_key, b"SMB3ENC");
+        let mac_key = Self::derive_mac_key(session_key, b"SMB3MAC");
+        
+        Ok(Self {
+            encryption_key,
+            mac_key,
+            cipher_algorithm,
+        })
+    }
+    
+    pub fn encrypt_packet(&self, plaintext: &[u8], session_id: u64) -> Result<Vec<u8>, EncryptionError> {
+        let nonce_bytes = self.generate_nonce();
+        
+        // 1. Compute HMAC over plaintext + header info (MtE mode)
+        let tag = self.compute_mac(plaintext, session_id, &nonce_bytes);
+        
+        // 2. Encrypt plaintext with AES-CTR
+        let encrypted_data = self.encrypt_aes_ctr(plaintext, &nonce_bytes);
+        
+        let header = TransformHeader {
+            cipher_algorithm: self.cipher_algorithm as u16,
+            cipher_key_length: 16,
+            nonce: nonce_bytes,
+            session_id,
+            original_message_size: plaintext.len() as u32,
+            reserved1: 0,
+            reserved2: 0,
+            signature: tag,
+        };
+        
+        let mut packet = header.write_to_bytes()?;
+        packet.extend_from_slice(&encrypted_data);
+        
+        Ok(packet)
+    }
+    
+    pub fn decrypt_packet(&self, encrypted_packet: &[u8]) -> Result<Vec<u8>, EncryptionError> {
+        let header = TransformHeader::read_from_bytes(encrypted_packet)?;
+        
+        let encrypted_data = &encrypted_packet[TransformHeader::SIZE..];
+        
+        // 1. Decrypt with AES-CTR
+        let plaintext = self.decrypt_aes_ctr(encrypted_data, &header.nonce);
+        
+        // 2. Verify HMAC
+        let expected_tag = self.compute_mac(&plaintext, header.session_id, &header.nonce);
+        if header.signature != expected_tag {
+            return Err(EncryptionError::InvalidSignature);
+        }
+        
+        Ok(plaintext)
+    }
+    
+    fn encrypt_aes_ctr(&self, plaintext: &[u8], nonce: &[u8; 16]) -> Vec<u8> {
+        use aes::cipher::{KeyIvInit, StreamCipher};
+        
+        let key = aes::cipher::generic_array::GenericArray::from_slice(&self.encryption_key);
+        let iv = aes::cipher::generic_array::GenericArray::from_slice(nonce);
+        
+        let mut cipher = Ctr128BE::<Aes128>::new(key, iv);
+        let mut ciphertext = plaintext.to_vec();
+        cipher.apply_keystream(&mut ciphertext);
+        
+        ciphertext
+    }
+    
+    fn decrypt_aes_ctr(&self, ciphertext: &[u8], nonce: &[u8; 16]) -> Vec<u8> {
+        self.encrypt_aes_ctr(ciphertext, nonce)  // CTR is symmetric
+    }
+    
+    fn compute_mac(&self, data: &[u8], session_id: u64, nonce: &[u8; 16]) -> [u8; 16] {
+        let mut mac = <HmacSha256 as Mac>::new_from_slice(&self.mac_key)
+            .expect("HMAC key length is valid");
+        
+        // MAC over: nonce + session_id + data
+        mac.update(nonce);
+        mac.update(&session_id.to_le_bytes());
+        mac.update(data);
+        
+        let result = mac.finalize();
+        let mut tag = [0u8; 16];
+        tag.copy_from_slice(&result.into_bytes()[..16]);
+        tag
+    }
+    
+    fn generate_nonce(&self) -> [u8; 16] {
+        let mut nonce = [0u8; 16];
+        getrandom::fill(&mut nonce).ok();
+        nonce
+    }
+    
+    fn derive_encryption_key(session_key: &[u8], context: &[u8]) -> [u8; 16] {
+        use sha2::{Sha256, Digest};
+        
+        let mut hasher = Sha256::new();
+        hasher.update(session_key);
+        hasher.update(context);
+        
+        let result = hasher.finalize();
+        let mut key = [0u8; 16];
+        key.copy_from_slice(&result[..16]);
+        key
+    }
+    
+    fn derive_mac_key(session_key: &[u8], context: &[u8]) -> [u8; 32] {
+        use sha2::{Sha256, Digest};
+        
+        let mut hasher = Sha256::new();
+        hasher.update(session_key);
+        hasher.update(context);
+        
+        let result = hasher.finalize();
+        let mut key = [0u8; 32];
+        key.copy_from_slice(&result[..32]);
+        key
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    
+    #[test]
+    fn test_cipher_algorithm_conversion() {
+        assert_eq!(CipherAlgorithm::from_u16(0x0001), Some(CipherAlgorithm::Aes128Gcm));
+        assert_eq!(CipherAlgorithm::from_u16(0x0002), Some(CipherAlgorithm::Aes128Ccm));
+        assert_eq!(CipherAlgorithm::from_u16(0x0003), None);
+    }
+    
+    #[test]
+    fn test_encrypt_decrypt_roundtrip() {
+        let session_key = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
+        let encryption = Smb3Encryption::new(&session_key, CipherAlgorithm::Aes128Gcm).unwrap();
+        
+        let plaintext = b"Hello SMB3!";
+        let session_id = 12345u64;
+        
+        let encrypted = encryption.encrypt_packet(plaintext, session_id).unwrap();
+        
+        // Debug: check header size
+        assert_eq!(encrypted.len(), TransformHeader::SIZE + plaintext.len());
+        
+        // Debug: check magic
+        let magic = u32::from_be_bytes([encrypted[0], encrypted[1], encrypted[2], encrypted[3]]);
+        assert_eq!(magic, 0x534D4220);
+        
+        let decrypted = encryption.decrypt_packet(&encrypted).unwrap();
+        
+        assert_eq!(plaintext.as_slice(), decrypted.as_slice());
+    }
+    
+    #[test]
+    fn test_invalid_signature_detection() {
+        let session_key = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
+        let encryption = Smb3Encryption::new(&session_key, CipherAlgorithm::Aes128Gcm).unwrap();
+        
+        let plaintext = b"Hello SMB3!";
+        let session_id = 12345u64;
+        
+        let encrypted = encryption.encrypt_packet(plaintext, session_id).unwrap();
+        
+        // Tamper with signature
+        let mut tampered = encrypted.clone();
+        tampered[48] ^= 0xFF;  // Modify signature byte
+        
+        let result = encryption.decrypt_packet(&tampered);
+        assert!(result.is_err());
+        assert_eq!(result.unwrap_err().to_string(), "Invalid transform header signature");
+    }
+}
\ No newline at end of file
