fix(crypto): K-01 — format v3 canonical metadata authentication

This commit is contained in:
2026-09-19 00:26:27 +02:00
parent 151fdba09d
commit ad531d8393
7 changed files with 609 additions and 12 deletions
+54 -1
View File
@@ -8,7 +8,7 @@ use zeroize::Zeroizing;
use sanctum::crypto::{
check_password_prefix_collision, dek_to_mnemonic, derive_kek, generate_dek, generate_salt,
mnemonic_to_dek, set_allow_legacy_names, validate_password, wrap_slot0_payload,
wrap_slot1_payload, KdfParams, FORMAT_VERSION,
wrap_slot1_payload, KdfParams, FORMAT_VERSION, FORMAT_VERSION_V3,
};
use sanctum::mount::{format_drive, mount_container, unmount_drive, ContainerAuth};
use sanctum::recovery::{
@@ -280,6 +280,13 @@ enum Commands {
#[arg(long, default_value_t = false)]
insecure_url: bool,
},
/// Migriert einen bestehenden Container auf Format V3 (Metadaten-Authentifizierung & Replay-Schutz)
UpgradeFormat {
/// Pfad zur .sanctum Containerdatei
#[arg(short, long)]
path: PathBuf,
},
}
fn parse_drive_letter(s: &str) -> Result<char> {
@@ -623,6 +630,7 @@ fn handle_init(
let db =
Database::open(container_path).context("Konnte SQLite-Containerdatei nicht anlegen")?;
db.set_active_dek(dek.clone());
db.init_schema_with_carrier(
&salt,
&kdf_params,
@@ -1214,6 +1222,48 @@ fn handle_verify(container_path: &Path, full: bool) -> Result<()> {
Ok(())
}
fn handle_upgrade_format(container_path: &Path) -> Result<()> {
if !container_path.exists() {
bail!(
"Containerdatei '{}' existiert nicht.",
container_path.display()
);
}
println!("┌─────────────────────────────────────────────────────────────┐");
println!("│ Sanctum — Format V3 Upgrade │");
println!("└─────────────────────────────────────────────────────────────┘");
println!(" Container: {}", container_path.display());
println!();
let password = rpassword::prompt_password("Master-Passwort: ")
.context("Fehler beim Einlesen des Passworts")?;
let db = Database::open(container_path).context("Konnte Container-Datenbank nicht öffnen")?;
let keys = match db.authenticate_password(&password)? {
Some(k) => k,
None => {
bail!("Authentifizierung fehlgeschlagen: Falsches Passwort");
}
};
if keys.version() >= FORMAT_VERSION_V3 {
println!(
" • Container ist bereits Format V{} (keine Migration erforderlich).",
keys.version()
);
return Ok(());
}
db.upgrade_to_v3(keys.dek())?;
db.checkpoint()?;
println!(" ✔ Container erfolgreich auf Format V3 aktualisiert!");
println!(" • Metadaten-Authentifizierung (HMAC-SHA256) aktiviert.");
println!(" • Replay-Schutz für Chunks (24-Byte AAD mit Generation) aktiviert.");
Ok(())
}
fn handle_sync(
container_path: &Path,
source: &str,
@@ -1520,6 +1570,9 @@ async fn run() -> Result<()> {
Commands::Verify { path, full } => {
handle_verify(&path, full)?;
}
Commands::UpgradeFormat { path } => {
handle_upgrade_format(&path)?;
}
Commands::Sync {
path,
source,