fix(carrier): C-02 — rolling dual-block manifest redundancy and failover recovery

This commit is contained in:
2026-09-19 11:59:51 +02:00
parent ca6d54d5ca
commit 8455dc02db
3 changed files with 339 additions and 28 deletions
+43 -16
View File
@@ -731,36 +731,63 @@ impl Database {
],
)?;
// Initialisiere CarrierManifest für Block 0
// Initialisiere CarrierManifest für redundante Blöcke 0 und 1 (C-02)
let manifest = crate::carrier::CarrierManifest::new(total_blocks);
let manifest_bytes = serde_json::to_vec(&manifest)?;
let (inner_ct, inner_nonce, inner_tag) =
// 1. Block 0 schreiben (Primärkopie, Gen 0)
let (inner_ct_0, inner_nonce_0, inner_tag_0) =
crate::crypto::encrypt_chunk(dek_1, c_id, 0, &manifest_bytes, FORMAT_VERSION, 0)?;
let inner_ct_len = inner_ct.len() as u32;
let inner_ct_len_0 = inner_ct_0.len() as u32;
let mut outer_plaintext = vec![0u8; CHUNK_SIZE];
OsRng.fill_bytes(&mut outer_plaintext);
let mut outer_plaintext_0 = vec![0u8; CHUNK_SIZE];
OsRng.fill_bytes(&mut outer_plaintext_0);
outer_plaintext[0..12].copy_from_slice(&inner_nonce);
outer_plaintext[12..28].copy_from_slice(&inner_tag);
outer_plaintext[28..32].copy_from_slice(&inner_ct_len.to_le_bytes());
let ct_end = 32 + inner_ct.len();
if ct_end > CHUNK_SIZE {
outer_plaintext_0[0..12].copy_from_slice(&inner_nonce_0);
outer_plaintext_0[12..28].copy_from_slice(&inner_tag_0);
outer_plaintext_0[28..32].copy_from_slice(&inner_ct_len_0.to_le_bytes());
let ct_end_0 = 32 + inner_ct_0.len();
if ct_end_0 > CHUNK_SIZE {
bail!("Manifest-Payload zu groß für Block 0");
}
outer_plaintext[32..ct_end].copy_from_slice(&inner_ct);
outer_plaintext_0[32..ct_end_0].copy_from_slice(&inner_ct_0);
let (outer_ct, outer_nonce, outer_tag) =
crate::crypto::encrypt_chunk(dek_0, c_id, 0, &outer_plaintext, FORMAT_VERSION, 0)?;
let (outer_ct_0, outer_nonce_0, outer_tag_0) =
crate::crypto::encrypt_chunk(dek_0, c_id, 0, &outer_plaintext_0, FORMAT_VERSION, 0)?;
conn.execute(
"INSERT INTO chunks (node_id, chunk_index, generation, nonce, tag, ciphertext)
VALUES (?1, 0, 0, ?2, ?3, ?4)",
params![c_id, outer_nonce.as_slice(), outer_tag.as_slice(), outer_ct],
params![c_id, outer_nonce_0.as_slice(), outer_tag_0.as_slice(), outer_ct_0],
)?;
// Blöcke 1..total_blocks-1 mit DEK_0 vorallokieren
// 2. Block 1 schreiben (Redundante Zweitkopie, Gen 0, C-02)
let (inner_ct_1, inner_nonce_1, inner_tag_1) =
crate::crypto::encrypt_chunk(dek_1, c_id, 1, &manifest_bytes, FORMAT_VERSION, 0)?;
let inner_ct_len_1 = inner_ct_1.len() as u32;
let mut outer_plaintext_1 = vec![0u8; CHUNK_SIZE];
OsRng.fill_bytes(&mut outer_plaintext_1);
outer_plaintext_1[0..12].copy_from_slice(&inner_nonce_1);
outer_plaintext_1[12..28].copy_from_slice(&inner_tag_1);
outer_plaintext_1[28..32].copy_from_slice(&inner_ct_len_1.to_le_bytes());
let ct_end_1 = 32 + inner_ct_1.len();
if ct_end_1 > CHUNK_SIZE {
bail!("Manifest-Payload zu groß für Block 1");
}
outer_plaintext_1[32..ct_end_1].copy_from_slice(&inner_ct_1);
let (outer_ct_1, outer_nonce_1, outer_tag_1) =
crate::crypto::encrypt_chunk(dek_0, c_id, 1, &outer_plaintext_1, FORMAT_VERSION, 0)?;
conn.execute(
"INSERT INTO chunks (node_id, chunk_index, generation, nonce, tag, ciphertext)
VALUES (?1, 1, 0, ?2, ?3, ?4)",
params![c_id, outer_nonce_1.as_slice(), outer_tag_1.as_slice(), outer_ct_1],
)?;
// Blöcke 2..total_blocks-1 mit DEK_0 vorallokieren (C-02)
let mut chunk_stmt = conn.prepare(
"INSERT INTO chunks (node_id, chunk_index, generation, nonce, tag, ciphertext)
VALUES (?1, ?2, 0, ?3, ?4, ?5)",
@@ -770,7 +797,7 @@ impl Database {
OsRng.fill_bytes(&mut dummy_noise);
conn.execute_batch("BEGIN TRANSACTION;")?;
for b in 1..total_blocks {
for b in 2..total_blocks {
let (ct, nonce, tag) =
crate::crypto::encrypt_chunk(dek_0, c_id, b, &dummy_noise, FORMAT_VERSION, 0)?;
chunk_stmt.execute(params![c_id, b, nonce.as_slice(), tag.as_slice(), ct,])?;