fix(crypto): K-03 — emergency card persistence warning and rekey command
This commit is contained in:
@@ -427,6 +427,73 @@ pub fn restore_header_from_recovery_key(
|
||||
restore_slot_from_recovery_key(container_path, recovery_key, new_password, 0, None)
|
||||
}
|
||||
|
||||
/// Führt ein vollständiges Rekeying eines Containers durch (K-03).
|
||||
/// Generiert einen neuen kryptografischen DEK, verschlüsselt alle Chunks um,
|
||||
/// verpackt den neuen DEK mit dem bestehenden Passwort und gibt das neue
|
||||
/// 24-Wort Notfallblatt (BIP-39 Mnemonic) zurück.
|
||||
/// Das alte Notfallblatt wird dadurch unwiderruflich ungültig.
|
||||
pub fn rekey_container(container_path: &Path, password: &str) -> Result<String> {
|
||||
if !container_path.exists() {
|
||||
bail!(
|
||||
"Containerdatei '{}' existiert nicht.",
|
||||
container_path.display()
|
||||
);
|
||||
}
|
||||
|
||||
let db = Database::open(container_path).context("Konnte Container-Datenbank nicht öffnen")?;
|
||||
let meta = db
|
||||
.read_meta()
|
||||
.context("Konnte Container-Header nicht lesen")?;
|
||||
let keys = meta.authenticate(password).ok_or_else(|| {
|
||||
anyhow::anyhow!("Ungültiges Master-Passwort! Authentifizierung fehlgeschlagen.")
|
||||
})?;
|
||||
|
||||
let old_dek = keys.dek().clone();
|
||||
let slot_id = keys.slot_id();
|
||||
let version = keys.version();
|
||||
let carrier_dek = keys.carrier_dek();
|
||||
let carrier_node_id = keys.carrier_node_id();
|
||||
|
||||
// 1. Neuen DEK generieren
|
||||
let new_dek = crate::crypto::generate_dek();
|
||||
|
||||
// 2. Chunks des aktiven Vaults umverschlüsseln
|
||||
db.rekey_vault(slot_id, &old_dek, &new_dek, version)?;
|
||||
|
||||
// 3. Neuen KEK ableiten und DEK neu verpacken
|
||||
let new_salt = crate::crypto::generate_salt();
|
||||
let new_params = KdfParams::default();
|
||||
let new_kek = derive_kek(password, &new_salt, &new_params)?;
|
||||
|
||||
let (new_wrapped_dek, new_nonce, new_tag) = if slot_id == 1 {
|
||||
let c_dek = carrier_dek
|
||||
.ok_or_else(|| anyhow::anyhow!("DEK_0 (Träger-Schlüssel) für Slot 1 fehlt"))?;
|
||||
let c_nid = carrier_node_id.unwrap_or(0);
|
||||
wrap_slot1_payload(&new_kek, &new_dek, &c_dek, c_nid)?
|
||||
} else {
|
||||
let c_nid = carrier_node_id.unwrap_or(0);
|
||||
wrap_slot0_payload(&new_kek, &new_dek, c_nid)?
|
||||
};
|
||||
|
||||
db.update_slot_keys(
|
||||
slot_id,
|
||||
&new_salt,
|
||||
&new_params,
|
||||
&new_wrapped_dek,
|
||||
&new_nonce,
|
||||
&new_tag,
|
||||
)?;
|
||||
|
||||
// 4. Metadaten-MAC mit neuem DEK aktualisieren
|
||||
db.set_active_slot_and_dek(slot_id, new_dek.clone());
|
||||
db.update_metadata_mac()?;
|
||||
db.checkpoint()?;
|
||||
|
||||
// 5. Neues BIP-39 Notfallblatt generieren
|
||||
let new_phrase = crate::crypto::dek_to_mnemonic(&new_dek)?;
|
||||
Ok(new_phrase)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
Reference in New Issue
Block a user