feat(recovery): implement header backup/restore, BIP-39 recovery key, and integrity verification
This commit is contained in:
+33
-14
@@ -12,11 +12,18 @@ use tokio::net::TcpListener;
|
||||
use tokio::sync::watch;
|
||||
use tracing::{debug, warn};
|
||||
|
||||
use crate::crypto::{derive_kek, unwrap_dek};
|
||||
use crate::crypto::{derive_kek, mnemonic_to_dek, unwrap_dek};
|
||||
use crate::storage::Database;
|
||||
use crate::ui;
|
||||
use crate::vfs::SanctumFs;
|
||||
|
||||
/// Authentifizierungsmethode für das Einbinden eines Containers: Entweder Master-Passwort oder 24-Wort Notfallschlüssel.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ContainerAuth {
|
||||
Password(String),
|
||||
RecoveryKey(String),
|
||||
}
|
||||
|
||||
/// Hilfsfunktion zur Formatierung des Laufwerksbuchstabens (z. B. 'S' -> "S:")
|
||||
pub fn format_drive(drive_letter: char) -> String {
|
||||
format!("{}:", drive_letter.to_ascii_uppercase())
|
||||
@@ -73,7 +80,7 @@ pub async fn mount_container(
|
||||
container_path: &Path,
|
||||
drive_letter: char,
|
||||
requested_port: Option<u16>,
|
||||
password: &str,
|
||||
auth: ContainerAuth,
|
||||
) -> Result<()> {
|
||||
let drive_str = format_drive(drive_letter);
|
||||
|
||||
@@ -93,21 +100,33 @@ pub async fn mount_container(
|
||||
.read_meta()
|
||||
.context("Konnte Container-Header nicht lesen")?;
|
||||
|
||||
ui::step(2, 4, "🔑", "Leite KEK via Argon2id ab...");
|
||||
let kek = derive_kek(password, &meta.kdf_salt, &meta.kdf_params)
|
||||
.context("Schlüsselableitung fehlgeschlagen")?;
|
||||
let (dek, version) = match auth {
|
||||
ContainerAuth::Password(ref password) => {
|
||||
ui::step(2, 4, "🔑", "Leite KEK via Argon2id ab...");
|
||||
let kek = derive_kek(password, &meta.kdf_salt, &meta.kdf_params)
|
||||
.context("Schlüsselableitung fehlgeschlagen")?;
|
||||
|
||||
ui::step(3, 4, "🔓", "Entschlüssele DEK via AES-256-GCM...");
|
||||
let dek = unwrap_dek(
|
||||
&kek,
|
||||
&meta.wrapped_dek,
|
||||
&meta.header_nonce,
|
||||
&meta.header_tag,
|
||||
)
|
||||
.context("Ungültiges Master-Passwort oder Container beschädigt")?;
|
||||
ui::step(3, 4, "🔓", "Entschlüssele DEK via AES-256-GCM...");
|
||||
let dek = unwrap_dek(
|
||||
&kek,
|
||||
&meta.wrapped_dek,
|
||||
&meta.header_nonce,
|
||||
&meta.header_tag,
|
||||
)
|
||||
.context("Ungültiges Master-Passwort oder Container beschädigt")?;
|
||||
(dek, meta.version)
|
||||
}
|
||||
ContainerAuth::RecoveryKey(ref phrase) => {
|
||||
ui::step(2, 4, "🔑", "Dekodiere DEK aus 24-Wort Notfallschlüssel...");
|
||||
let dek = mnemonic_to_dek(phrase)
|
||||
.context("Ungültiger 24-Wort Notfallschlüssel")?;
|
||||
ui::step(3, 4, "🔓", "Notfallschlüssel erfolgreich verifiziert!");
|
||||
(dek, meta.version)
|
||||
}
|
||||
};
|
||||
|
||||
// WebDAV Filesystem und Handler konfigurieren
|
||||
let fs = SanctumFs::new(db.clone(), dek, meta.version);
|
||||
let fs = SanctumFs::new(db.clone(), dek, version);
|
||||
let dav_server = DavHandler::builder()
|
||||
.filesystem(Box::new(fs))
|
||||
.locksystem(FakeLs::new())
|
||||
|
||||
Reference in New Issue
Block a user